资讯

精准传达 • 有效沟通

从品牌网站建设到网络营销策划,从策略到执行的一站式服务

java代码效率优化 java怎么优化代码减少内存

Java代码如何优化

1. 尽量在合适的场合使用单例

成都创新互联长期为上千多家客户提供的网站建设服务,团队从业经验10年,关注不同地域、不同群体,并针对不同对象提供差异化的产品和服务;打造开放共赢平台,与合作伙伴共同营造健康的互联网生态环境。为剑阁企业提供专业的成都网站设计、网站建设,剑阁网站改版等技术服务。拥有10年丰富建站经验和众多成功案例,为您定制开发。

使用单例可以减轻加载的负担,缩短加载的时间,提高加载的效率,但并不是所有地方都适用于单例,简单来说,单例主要适用于以下三个方面:

第一,控制资源的使用,通过线程同步来控制资源的并发访问;

第二,控制实例的产生,以达到节约资源的目的;

第三,控制数据共享,在不建立直接关联的条件下,让多个不相关的进程或线程之间实现通信。

2. 尽量避免随意使用静态变量

要知道,当某个对象被定义为stataic变量所引用,那么gc通常是不会回收这个对象所占有的内存

3. 尽量避免过多过常的创建Java对象

尽量避免在经常调用的方法,循环中new对象,由于系统不仅要花费时间来创建对象,而且还要花时间对这些对象进行垃圾回收和处理,在我们可以控制的范围内,最大限度的重用对象,最好能用基本的数据类型或数组来替代对象。

4. 尽量使用final修饰符

带有final修饰符的类是不可派生的。在Java核心API中,有许多应用final的例子,例如java.lang.String.为String类指定final防止了使用者覆盖length()方法。另外,如果一个类是final的,则该类所有方法都是final的。Java编译器会寻找机会内联(inline)所有的final方法(这和具体的编译器实现有关)。此举能够使性能平均提高50%.

5. 尽量使用局部变量

调用方法时传递的参数以及在调用中创建的临时变量都保存在栈(Stack)中,速度较快。其他变量,如静态变量、实例变量等,都在堆(Heap)中创建,速度较慢。

6. 尽量处理好包装类型和基本类型两者的使用场所

虽然包装类型和基本类型在使用过程中是可以相互转换,但它们两者所产生的内存区域是完全不同的,基本类型数据产生判凳仿和处理都在栈中处理,包装类型是对象,是在堆中产生实例。

在集合类对象,有对象方面需要的处理适用包装类型,其他的处理提倡使用基本类型。

7. 慎用synchronized,尽量减小synchronize的方法

都知道,实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。synchronize方法被调用时,直接会把当前对象锁 了,在方法执行完之前其他线程无法调用当前对象的其他方法。所以synchronize的方法尽量小,并且应尽量使用方法同步代替代码块同步。

8. 尽量使用StringBuilder和StringBuffer进行字符串连接

这个就不多讲了。

9. 尽量不要使用finalize方法

实际上,将资源清理放在finalize方法中完成是非常掘纤不好的选择,由于GC的工作量很大,尤其是回收Young代内存时,大都会引起应用程序暂停,所以再选择使用finalize方法进行资源清理,会导致GC负担更大,程序运行效率更差。

10. 尽量使用基本数据类型代替对象

String str = "hello";

上面这种方式会创建一个"hello"字符串,而且JVM的字符缓存池还会缓存这个字符串;

String str = new String("hello");

此时程序除创建字符串外,str所引用的String对象底层还包含一个char[]数组,这个char[]数组依次存放了h,e,l,l,o

11. 单线程应尽量使用HashMap、ArrayList

HashTable、Vector等使用了同步机制,降低了性能。

12. 尽量合理的创建HashMap

当你要创建一个比较大的hashMap时,充分利用另一个构造函数

public HashMap(int initialCapacity, float loadFactor)

避免HashMap多次进行了hash重构,扩容是一件很耗费性能的事,在默认中initialCapacity只有16,而loadFactor是 0.75,需要多大的容量,你最好能准确的估计你所需要的最佳大小,同样的Hashtable,Vectors也是一样的道理。

13. 尽量减少对变量的重复计算

并且在循环中应该避免使用复杂的表达式,在循环中,循环条件会被反复计算,如果不使用复杂表达式,而使循环条件值不变的话,程序将会运行的更快。

14. 尽量避免不必要的创建

15. 尽量在finally块中释放资源

程序中使用到的资源应当被释放,以避免资源泄漏。这最好在finally块粗祥中去做。不管程序执行的结果如何,finally块总是会执行的,以确保资源的正确关闭。

16. 尽量使用移位来代替'a/b'的操作

"/"是一个代价很高的操作,使用移位的操作将会更快和更有效

17.尽量使用移位来代替'a*b'的操作

同样的,对于'*'操作,使用移位的操作将会更快和更有效

18. 尽量确定StringBuffer的容量

StringBuffer 的构造器会创建一个默认大小(通常是16)的字符数组。在使用中,如果超出这个大小,就会重新分配内存,创建一个更大的数组,并将原先的数组复制过来,再 丢弃旧的数组。在大多数情况下,你可以在创建 StringBuffer的时候指定大小,这样就避免了在容量不够的时候自动增长,以提高性能。

19. 尽量早释放无用对象的引用

大部分时,方法局部引用变量所引用的对象 会随着方法结束而变成垃圾,因此,大部分时候程序无需将局部,引用变量显式设为null.

20. 尽量避免使用二维数组

二维数据占用的内存空间比一维数组多得多,大概10倍以上。

21. 尽量避免使用split

除非是必须的,否则应该避免使用split,split由于支持正则表达式,所以效率比较低,如果是频繁的几十,几百万的调用将会耗费大量资源,如果确实需 要频繁的调用split,可以考虑使用apache的StringUtils.split(string,char),频繁split的可以缓存结果。

22. ArrayList LinkedList

一 个是线性表,一个是链表,一句话,随机查询尽量使用ArrayList,ArrayList优于LinkedList,LinkedList还要移动指 针,添加删除的操作LinkedList优于ArrayList,ArrayList还要移动数据,不过这是理论性分析,事实未必如此,重要的是理解好2 者得数据结构,对症下药。

23. 尽量使用System.arraycopy ()代替通过来循环复制数组

System.arraycopy() 要比通过循环来复制数组快的多

24. 尽量缓存经常使用的对象

尽可能将经常使用的对象进行缓存,可以使用数组,或HashMap的容器来进行缓存,但这种方式可能导致系统占用过多的缓存,性能下降,推荐可以使用一些第三方的开源工具,如EhCache,Oscache进行缓存,他们基本都实现了FIFO/FLU等缓存算法。

25. 尽量避免非常大的内存分配

有时候问题不是由当时的堆状态造成的,而是因为分配失败造成的。分配的内存块都必须是连续的,而随着堆越来越满,找到较大的连续块越来越困难。

26. 慎用异常

当创建一个异常时,需要收集一个栈跟踪(stack track),这个栈跟踪用于描述异常是在何处创建的。构建这些栈跟踪时需要为运行时栈做一份快照,正是这一部分开销很大。当需要创建一个 Exception 时,JVM 不得不说:先别动,我想就您现在的样子存一份快照,所以暂时停止入栈和出栈操作。栈跟踪不只包含运行时栈中的一两个元素,而是包含这个栈中的每一个元素。

如 果您创建一个 Exception ,就得付出代价。好在捕获异常开销不大,因此可以使用 try-catch 将核心内容包起来。从技术上讲,您甚至可以随意地抛出异常,而不用花费很大的代价。招致性能损失的并不是 throw 操作--尽管在没有预先创建异常的情况下就抛出异常是有点不寻常。真正要花代价的是创建异常。幸运的是,好的编程习惯已教会我们,不应该不管三七二十一就 抛出异常。异常是为异常的情况而设计的,使用时也应该牢记这一原则。

(1)。 用Boolean.valueOf(boolean b)代替new Boolean()

包装类的内存占用是很恐怖的,它是基本类型内存占用的N倍(N2),同时new一个对象也是性能的消耗。

(2)。 用Integer.valueOf(int i)代替new Integer()

和Boolean类似,java开发中使用Integer封装int的场合也非常多,并且通常用int表示的数值都非常小。SUN SDK中对Integer的实例化进行了优化,Integer类缓存了-128到127这256个状态的Integer,如果使用 Integer.valueOf(int i),传入的int范围正好在此内,就返回静态实例。这样如果我们使用Integer.valueOf代替new Integer的话也将大大降低内存的占用。

(3)。 用StringBuffer的append方法代替"+"进行字符串相加。

这个已经被N多人说过N次了,这个就不多说了。

(4)。 避免过深的类层次结构和过深的方法调用。

因为这两者都是非常占用内存的(特别是方法调用更是堆栈空间的消耗大户)。

(5)。 变量只有在用到它的时候才定义和实例化。

这是初学者最容易犯的错,合理的使用变量,并且只有在用到它的时候才定义和实例化,能有效的避免内存空间和执行性能上的浪费,从而提高了代码的效率。

(6)。 避免在循环体中声明创建对象,即使该对象占用内存空间不大。

这种情况在我们的实际应用中经常遇到,而且我们很容易犯类似的错误

采用上面的第二种编写方式,仅在内存中保存一份对该对象的引用,而不像上面的第一种编写方式中代码会在内存中产生大量的对象引用,浪费大量的内存空间,而且增大了垃圾回收的负荷。因此在循环体中声明创建对象的编写方式应该尽量避免。

(7)。 如果if判断中多个条件用'||'或者''连接,请将出现频率最高的条件放在表达式最前面。

这个小技巧往往能有效的提高程序的性能,尤其是当if判断放在循环体里面时,效果更明显。

1.JVM管理两种类型的内存:堆内存(heap),栈内存(stack),堆内在主要用来存储程序在运行时创建或实例化的对象与变量。而栈内存则是用来存储程序代码中声明为静态(static)(或非静态)的方法。

2.JVM中对象的生命周期,创建阶段,应用阶段,不可视阶段,不可到达阶段,可收集阶段,终结阶段,释放阶段

3.避免在循环体中创建对象,即使该对象点用内存空间不大。

4.软引用的主要特点是具有较强的引用功能。只有当内存不够的时候,才回收这类内存,因此在内存足够的时候,它们通常不被回收。它可以用于实现一些常用资源的缓存,实现Cache的功能

5.弱引用对象与Soft引用对象最大不同就在于:GC在进行回收时,需要通过算法检查是否回收Soft引用对象,而对于Weak引用对象,GC总是进行回收。

6.共享静态变量存储空间

7.有时候我们为了提高系统性能,避免重复耗时的操作,希望能够重用一些创建完成的对象,利用对象池实现。类似JDBC连接池。

8.瞬间值,序列化对象大变量时,如果此大变量又没有用途,则使用transient声明,不序列化此变量。同时网络传输中也不传输。

9.不要提前创建对象

10 .(1)最基本的建议就是尽早释放无用对象的引用

A a = new A();

a = null; //当使用对象a之后主动将其设置为空

(2)尽量少用finalize函数。

(3) 如果需要使用经常用到的图片展,可以使用软引用。

(4) 注意集合数据类型,包括数组,树等数据,这些数据结构对GC来说,回收更为复杂,

(5) 尽量避免在类的默认构造器中创建,初始化大量的对象,防止在调用其自类的构造器时造成不必要的内存资源浪费。

(6) 尽量避免强制系统做垃圾内存回收。

(7) 尽量避免显式申请数组空间。

(8) 尽量在合适的场景下使用对象池技术以提高系统性能,缩减系统内存开销。

11.当做数组拷贝操作时,采用System.arraycopy()方法完成拷贝操作要比采用循环的办法完成数组拷贝操作效率高

12. 尽量避免在循环体中调用方法,因为方法调用是比较昂贵的。

13. 尽量避免在循环体中使用try-catch 块,最好在循环体外使用try--catch块以提高系统性能。

14. 在多重循环中,如果有可能,尽量将最长的循环放在最内层,最短的循环放在最外层,以减少循环层间的变换次数。

15. 在需要线程安全的情况下,使用List list = Collections.synchronizedList(new ArrayList());

16. 如果预知长度,就设置ArrayList的长度。

17. ArrayList 与 LinkedList 选择,熟悉底层的实现原理,选择适当的容器。

18. 字符串累加采用StringBuffer.

19. 系统I/O优化,采用缓冲和压缩技术。优化性能。

20. 避免在类在构造器的初始化其他类

21 尽量避免在构造中对静态变量做赋值操作

22. 不要在类的构造器中创建类的实例

23. 组合优化继承

24. 最好通过Class.forname() 动态的装载类

25. JSP优化,采用out 对象中的print方法代替println()方法

26 .采用ServletOutputStream 对象代替JSPWriter对象

27. 采用适当的值初始化out 对象缓冲区的大小

28. 尽量采用forward()方法重定向新的JSP

29. 利用线程池技术处理客户请求

30.Servlet优化

(1) 通过init()方法来缓存一些静态数据以提高应用性能。

(2) 用print() 方法取代println()方法。

(3) 用ServletOutputStream 取代 PrintWriter.

(4) 尽量缩小同步代码数量

31. 改善Servlet应用性能的方法

(1)不要使用SingleThreadModel

(2)使用线程池ThreadPool

32. EJB优化

实体EJB:

(1)实体EJB中常用数据缓存与释放

(2)采用延迟加载的方式装载关联数据

(3)尽可能地应用CMP类型实体EJB

(4)直接采用JDBC技术处理大型数据

33. 优化JDBC连接

(1)设置合适的预取行值

(2)采用连接池技术

(3)全合理应用事务

(4)选择合适的事务隔离层与及时关闭连接对象

34. PreparedStatemetn只编译解析一次,而Statement每次都编译解析。

35. 尽可能地做批处理更新

36. 通过采用合适的getXXX方法提高系统性能

37. 采用设计模式。

Java这段代码如何优化?List 对象和foreach有点多

1、把这些提炼到一个方法里面来完成扒告坦

2、一句sql语句能友谈搞定的就用一句sql语句。你写的查询多个表java代码肯定没有mysql的速度快

3、方法模块化,把功能尽量小化,然后春桐根据模块划分和封装

Java中利用Reflection API优化代码

摘要开发者通过各种各样的方法来尝试避免单调冗余的编程 一些编程的规则例如继承 多态或者设计模型可以帮助开发者避免产生多余的代码 不过由于软件开发方面存在着不确定性 因此这些规则并不能消除代码维护和重新编写的需要 在很多时候维护都是不可避免的 只有不能运作的软件才是从不需要维护的 不过 这篇文章介绍了你可以使用Java的Reflection API的功能来减少单调的代码编写 并可以使用活动的代码产生来克服reflection的限制 数据配置(由外部的源头得到数据并且将它装载到一个Java对象中)可以利用reflection的好处来创建一个可重用的方案 问题是很简单的 将数据由一个文件装入到一个对象的字段中 现在假设用作数据的目标Java类每星期改变一次?有一个很直接的解决方法 不过你必须不断地维护载入的过程来反映任何的改变 在更复杂的环境下 同样的问题可能会令系统崩溃掉 对于一个处理过运用XML的大型系统的人来说 他就会遇到过这个问题 要编写一个载入的过程通常是非常单调乏味的 由于数据源或者目标Java类的改变 你需要经常更新和重新编写代码 在这里我要介绍另一个解决方案 那就是使用映射 它通常使用更少的编码 并且可以在目标Java类发生改变后更新自己 最初 我想介绍一个使用Reflection在运枝宏行期间配置数据的方案 在开始的时候 一个动态 基于映射的程序要比一个简单的方法更有吸引力多了 随后 我要揭示出运行时Reflection的复杂性和冒险性 这篇文章将介绍由运行时的Reflection到活动的代码产生 由简单到复杂我的第一个方案使用一个载入类将数据从一个文件载入到对象中 我的源代码含有对StringTokenizer对象下一节点方法的多次调用 在修改多次后 我的编码逻辑变得非常的直接 系统化 该类构造了专用的代码 在这个初始方案中 我只需要使用 个基本的对象 Strings Objects Arrays of objects你可以影射类的对象来产生代码块 如下表所示 被影射来产生代码块的对象 我已经使用这个方案作了几次编码 因此我在写代码之前我已经知道该方案和代码的结构 难点在于该类是变化的 类的名字 成份和结构在任何时候都可能发生变化 而任何的改变你都要重新编写代码 虽然会发生这些变化 但是结构和下载的流程仍然是一样的 在写代码前 我仍然知道代码的结构和成份 我需要一个方法 来将头脑中的编码流程转换为一个可重用的 自动的形式 由于我是一个有效率的编程者 我很快就厌倦了编写几乎一样的代码 这时我想到了映射 数据配置通常需要一个源到目的数据的影射 影射可以是一个图解 DTD(document type definition 文档类型定义) 文件格式等 在这个例子中 映射将一个对象的类定义解释为我们要映射的流程 映射可以在运行时复制代码的功能 在需要重写代猛缺册码时 我将载入的过程用映射来代替 它所需要的时间和重写是一样的 载入的工程可以概括为以下几步 解释 一个影射决定你在构造一个对象时需要些什么 请求数据 要满足构造的需要 要进行一个调用来得到数据 拖 数据由源中得到 推 数据被填充入一个对象的新实例 如果必要的话 重复步骤 你需要以下的类来满足以上的步骤 .数据类(Data classes) 由ASCII文件中的数据实例化 类定义提供数据的影射 数据类必须满足以下的条件 它们必须包含有一个构造器来接收全部必需的参数 以使用一个有效的状态来构造对象 它们必须由对象构成 这些对象是reflective过程知道如何处理的.对象装载器(Object loader) 使用reflection和数据类作为一个影射来载入数据 产生数据请求 .载入管理器(Load manager) 作为对象装载器和数据源的扮派中介层 将对数据的请求转换为一个数据指定的调用 这可以令对象载入器做到与数据源无关 通过它的接口和一个可载入的类对象通信 .数据循环接口(Data iterator interface) 载入管理器和载入类对象使用这个接口来由数据源中得到数据 一旦你创建了支持的类 你就可以使用以下的声明来创建和影射一个对象 FooFileIterator iter = new FooFileIterator(fileLocation log);LoadManager manager = new FooFileLoadManager(iter);SubFooObject obj = (SubFooObject)ReflectiveObjectLoader initializeInstance(SubFooObject class manager log); 通过这个处理 你就创建了一个包含有文件内容的SubFooObject实例 局限开发者必须决定使用哪个方案来解决问题是最好的 通常做出这个决定是最困难的部分 在考虑使用reflection作数据配置时 你要考虑到以下一些限制 不要令一个简单的问题复杂化 reflection是比较复杂的 因此在必要的时候才使用它 一旦开发者明白了reflection的能力 他就想使用它来解决所有的问题 如果你有更快 更简单的方案来解决问题时 你就不应该使用reflection(即使这个更好的方案可能使用更多的代码) reflection是强大的 但也有一些风险 考虑性能 reflection对性能的影响比较大 因为要在运行时发现和管理类属性需要时间和内存 重新评估方案如上所述 使用运行时reflection的第一个限制是 不要令简单的问题复杂化 在使用reflection时 这是不可避免的 将reflection和递归结合起来是一个令人头痛的问题 重新看代码也是一件可怕的事情 而准确决定代码的功能也是非常复杂的 要知道代码的准确作用的唯一方法是使用一些取样数据 逐行地看 就象运行时一样 不过 对于每个可能的数据组合都使用这种方式几乎是不可能的 在这种情况下 使用单元测试代码可能有些帮助 不过也很可能出现错误 幸运的是 还有一个可选的方法 可选的方法由上面列出的限制可以看到 在某些情况下 使用reflective载入过程可能是得不偿失的 代码产生提供了一个通用的选择方法 你也可以使用reflection来检查一个类并且为载入过程产生代码 Andrew Hunt和David Thomas介绍了两类的代码产生器 见The Pragmatic Programmer( /jwl#resources) Passive(被动) 被动的代码产生器在实现代码时需要人工的干预 许多的IDE(集成开发环境)都提供相应的向导来实现 Active(主动) 主动的代码产生指的是代码一旦创建 就不再需要修改了 如果有问题产生 这个问题也应该在代码产生器中解决 而不是在产生的源文件中解决 在理想的情况下 这个过程应该包含在编译的处理过程中 从而确保类不会过期 代码产生的优点和缺点包含有以下方面 优点 .简单 产生的代码通常是更便于开发者阅读和调试 .编译过程的错误 Reflexive在运行时出现错误的机会要比编译的期间多 例如 改变被载入的对象将有可能令产生的载入类抛出一个编译的错误 不过reflexive过程将不会看到任何的区别 直到在运行时遇到这个类 缺点 .维护 使用被动的代码产生 修改被载入的对象将需要更新或者重新产生载入的类 如果该类被重新产生 那么自定义的东西就会丢失 回头再来看看主动代码产生的好处在这里我们可以看到在运行时使用reflection是不可以接受的 主动的代码产生有着reflection的全部好处 但是没有它的限制 还可以继续使用reflection 不过只是在代码的产生过程 而不是运行的过程 理由如下 更少冒险 运行时的reflection明显是更冒险的 特别是问题变得复杂的时候 基于单元测试 但并不是编译器 多功能性 产生的代码有着runtime reflection的全部好处 而且有着runtime reflection没有的好处 更易懂 虽然经过多次的处理 但是将递归和reflection结合仍然是很复杂的 产生源代码的方式更加容易解释和理解 代码产生过程需要递归和reflection 但得到的结果是可查看的源代码 而不是难以理解的东西 写代码产生器要写一个代码产生器 在思考的时候 你不能只是简单地编写一个方案来解决一个问题 你应该看得更远 代码产生器(以及reflection)需要你作更多的思考 如果你只是使用runtime reflection 你就不得不在运行时概念化问题 而不是使用简单 兼容性好的源代码来解决问题 代码产生要求你从两个方面来查看问题 代码产生过程会将抽象的概念转变为实际的源代码 Runtime reflection则一直是抽象的 代码产生过程将你的思考过程转变为代码 然后产生并且编译代码 编译器会让你知道你的思考过程在语法上是否正确 单元测试则可以验证代码在运行时的行为 就动态特性方面 runtime reflection就不能达到这个级别的安全性 代码产生器在经历后几次失败的设计后 我认为最简单的方法是 在载入过程中 为每一种需要实例化的类产生一个方法 一个方法工厂产生每个特别类的正确方法 一个代码编译对象缓冲来自代码工厂的方法请求 以产生最终源代码文件的内容 MethodCode对象是代码产生过程的核心 以下就是一个int的代码产生对象的例子 public class MethodForInt extends MethodCode {private final static MethodParameter param = new MethodParameter(SimpleFileIterator class parser );public MethodForInt(Class type CodeBuilder builder){super(type builder);}public MethodParameter[] getInputParameters(){return new MethodParameter[]{param};} lishixinzhi/Article/program/Java/hx/201311/25959


分享标题:java代码效率优化 java怎么优化代码减少内存
标题来源:http://cdkjz.cn/article/dshoejg.html
多年建站经验

多一份参考,总有益处

联系快上网,免费获得专属《策划方案》及报价

咨询相关问题或预约面谈,可以通过以下方式与我们联系

大客户专线   成都:13518219792   座机:028-86922220