java学习笔记

来源:互联网 发布:易语言编程怎么样 编辑:程序博客网 时间:2024/05/22 15:58

关于java内存优化的问题

 

注意事项:

1.别用new Boolean()

     在java JDBC(Java DataBase Connectivity)中boolean类型的set与get都是通过Boolean来封装传递的,大部分ORM也是用Boolean来封装boolean类型的,一般而言,系统中构造的Boolean实例的个数很多,所以系统中存在大量Boolean实例小对象,这个非常耗内存,Boolean类实际上仅需要两个实例,一个true,一个false

    Boolean类提供了两个静态变量:

    public static final Boolean TRUE = new Boolean(true);

    public static final Boolean FALSE = new Boolean(false);

     然后当要用到时,可以:

 

    /*

         *需要用到时:Connection conn; 省略部分代码

         *String sql = "SELECT * FROM users WHERE isPass = ?";

* PreparedStatement ps =conn.prepareStatement(sql);

* ps.setBoolean("isClosed",Boolean.TRUE); // 进行赋值

* ps.setBoolean("isClosed",Boolean.valueOf(isClosed));//根据一个boolean变量来创建Boolean

    *ps.setBoolean("isClosed",Boolean.valueOf(i==3));//根据一个boolean变量来创建Boolean

         *ps.executeQuery();

*

         *valueOf的内部实现为:return(b?TRUE:FALSE);

         */

 

boolean: 基本类型

Boolean: 对象类型 继承于 Object而很多的API函数要求传入Object类型这是boolean就要被包装成Boolean才行如果仅用于旗标那就用boolean就好了

2.别用new Integer

     和Boolean类似,java开发中使用Integer封装int的场合很多,通常int表示的数值也很小,SUNsdk中对Integer的实例化进行了优化,Integer类缓存了-128~127这256个状态的Integer,如果用Integer.valueOf(int i),传入的值在这个范围内,则返回静态实例。

     如果在不同的sdk中使用需要自己写一个工具类封装。

3.用StringBuffer代替字符串相加(StringBuffer和StringBuilder是有差别的,StringBuffer是线程同步的,所以效率会稍低)

   String的相加实际上是先转化为StringBuffer,而后调用StringBuffer的append方法将字符串相加而后用getValue获得String返回,由于String本质上是一个类,需要实例化,所以这样会创建很多个string实例。

4.过滥使用HashMap

    很多开发人员会用hash表来缓存数据,从而提高系统的运行速度,比如用HashMap缓存一些物料信息、人员信息等,在提高系统速度的同时加大了系统的内存占用,特别是当缓存资料较多时,我们可以用操作系统中的缓存概念来解决此问题,给缓存分配一个一定大小的缓存容器,

按照一定的算法淘汰不需要缓存的对象,这样因为进行了对象缓存提高了操作系统的运行效率,同时由于缓存容器大小有限,也减少了系统的内存占用。有很多开源项目如ehcache、oscache等都实现了fifo、mru等常见的缓存算法。

 

关于为什么用hash表可以提高系统的运行速度:http://blog.csdn.net/liu765023051/article/details/49408099

5.避免过深的类层次结构和过深的方法调用

这两者都是非常耗费内存的,其中方法调用更是堆栈空间的消耗大户。

6.变量在用到的时候才定义和实例化(懒汉模式)

7.尽量避免使用static变量

类内私有变量可以用final代替

关于static和final的区别:http://blog.csdn.net/tengdazhang770960436/article/details/25156743

 

 

Java内存管理的特点

Java的优点主要有:

1、取消了指针,由垃圾收集器来自动管理内存的回收。程序员不需要释放申请到的内存。

2、Java采用翻译、执行方式,可以跨平台。

 

一、java的内存管理就是对象的分配和释放问题。

在java中,程序员需要通过关键字new为每个对象申请内存空间(基本类型除外),左右的对象都在堆(Heap)中分配空间。

对象的释放是由GC决定和执行的,在java中,内存的分配是由程序完成的,而内存的释放是由GC完成的,这种方式简化了程序员的工作却加重了JVM的工作,这也是java程序运行速度较慢的原因之一。(关于GC机制的介绍http://blog.csdn.net/heyutao007/article/details/38151581)

GC释放空间的方法:

监控每一个对象的运行状态,包括对象的申请、引用、被引用、赋值等,具体算法在关于GC机制的介绍中有,比如标记删除法、标记整理法、复制删除法等。

二、内存管理结构

Java使用有向图的方式进行内存管理,对应程序的每个时刻,都有一个有向图

JVM的内存分配情况。具体方式为:

                   将对象考虑为有向图的顶点,将引用关系考虑为图的有向边,有向边从引用者只想被引用对象。另外,每个线程对象可以作为一个图的起始顶点,例如大多数程序从main进程开始执行,那么该图就是以main进程为顶点开始的一棵根数。在这个有向图中,根顶点可达的对象都是有效对象,GC将不回收这些对象,如果某个对象(连通子图)与这个根顶点不可达(该图为由向图),那么我们认为这个对象不再被引用,可以被GC回收。

三、使用有向图方式管理内存的优缺点

Java用有向图方式进行内存管理,可以消除引用循环的问题,这种方式的优点是管理内存的精度很高,可是效率较低。

 

Add:另外一种常用的内存管理技术是使用计数器,执行效率很高可是存在循环引用的问题。

Java的内存泄漏

Java虽然有GC机制来回收内存,较C++而言,java虽然泄漏较少但也是有泄漏的。

 

1.      关于C++

C++所有的对象的分配和回收都要用户来管理,如果出现不可达的点,无法回收分配给那个点的内存(比如使用过程中指针丢失),这时就会产生内存泄漏。

           Java用GC机制来管理内存,由于GC机制将会回收没有被引用的对象,从而可以解决不可达点的内存泄漏问题,可是如果对象仍被引用,但后期不会再去使用它,这个内存就浪费了(比如创建实例后没有置空,后期又不再使用该实例)

           对比下而言,实际上就是说在java中,不必担心引用的对象丢失的问题,而如果有实例在后期不再被使用,就应该将其置空。

2.      Java内存泄漏处理

典型的处理办法是将引用置空,如果变量是局部变量,则不需要置空,

这个方法执行完毕后引用将被清理。(注意,当内存的Eden区没有被填满时,GC将不会调用,所有变量不一定会马上被清除)

3.      对GC操作

对GC的操作不一定会达到期望的效果,GC对程序员而言是基本透明

不可见的。我们可以通过System.gc方法来运行gc,但是由于该函数并不保证jvm的垃圾收集器一定会执行,因为jvm的实现者可能用不同算法管理GC,一般而言GC的优先级比较低。

         Jvm调用GC的策略有多种,有的是内存使用到一定程度时GC才会开始工作,有定时执行的、有平缓执行的、有中断式执行的,但是通常而言,我们不需要关心,但是GC的执行会影响程度的性能,特别是在一些实时系统上,这时候我们需要调节GC的参数,让GC能够通过平缓的方式释放内存,其中HotSpot jvm就支持这一特性。

4.      内存泄漏检测

内存泄漏检测工具的基本工作原理都是通过检测java程序运行时,所有对象的申请、释放等动作,将内存管理的所有信息进行统计、分析、可视化。目前这些工具有:Optimizeit、Profiler、JProbe Profiler、JinSight、Rational公司的Purify等

5.      引用方式

1>    软引用(SoftReference)

软引用的特点是只有当内存不够的时候才会回收这类内存,同时又保证在java抛出OutOfMemory异常之前被设置为null。最大限度保证使用内存而又不会引起OOM。但是其也存在缺点,主要是当应用软引用的对象的初始化过程较为耗时,或者对象的状态在程序的运行过程中产生变化,这会给重新创建对象与初始化对象造成不同程度的麻烦。

            软引用的主要用途为:用于实现一些常用资源的缓存,实现Cache的功能,还可以处理一些占用内存大,且声明周期较长但是用却不频繁的对象。

            软引用的主要写法为:

2>    强引用(StrongReference)

强引用是最普遍的引用,如果一个对象有强引用,那么垃圾回收器将绝不会回收它,当内存不足时,宁愿报OOM也不会随意回收具有强引用的对象来解决内存不足的问题。

强引用的主要写法为:Aa=new A();

3>    弱引用(WeakReference)

弱引用与软引用的区别在于:只具有弱引用的对象拥有更短的生命

期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存,但是由于GC的优先级很低,不一定会很快发现那个对象。

弱引用可以与引用队列联合使用。引用队列:ReferenceQueue  关于引用与引用队列实例:http://www.2cto.com/kf/201403/285767.html 

4>    虚引用(PhantomReference)

虚引用就是形同虚设,虚引用不会决定对象的生命周期,如果一个

象仅持有虚引用,那和没有被引用是一样的,任何时候都可能被回收。

         虚引用与软引用的区别在于:虚引用必须和引用队列联合使用,当垃圾回收期准备回收一个对象时,如果发现它还有虚引用,就会把这个虚引用加入到与之关联的引用队列中,程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用对象是否将要被垃圾回收,从而在回收前采取必要的行动。

6.      如何使用软引用

http://blog.csdn.net/coding_or_coded/article/details/6603549

本文参考了:

http://blog.csdn.net/zheng0518/article/details/48182437

http://blog.csdn.net/liu765023051/article/details/49408099

http://blog.csdn.net/coding_or_coded/article/details/6603549

http://www.2cto.com/kf/201403/285767.html

http://blog.csdn.net/tengdazhang770960436/article/details/25156743

http://blog.csdn.net/tengdazhang770960436/article/details/25156743

感谢相应作者!

0 0