浅析JAVA之垃圾回收机制精品资料.doc
《浅析JAVA之垃圾回收机制精品资料.doc》由会员分享,可在线阅读,更多相关《浅析JAVA之垃圾回收机制精品资料.doc(31页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、浅析JAVA之垃圾回收机制 分类: JAVA应用开发 JVM 2010-05-22 22:03 401人阅读 评论(2) 收藏 举报 对于JAVA编程和很多类似C、C+语言有一个巨大区别就是内存不需要自己去free或者delete,而是由JVM垃圾回收机制去完成的。对于这个过程很多人一直比较茫然或者觉得很智能,使得在写程序的过程不太考虑它的感受,其实知道一些内在的原理,帮助我们编写更加优秀的代码是非常有必要的;本文介绍一些JVM垃圾回收的基本知识,后续的文章中会深入探讨JVM的内在;首先在看文章之前大家需要知道为什么要写JVM垃圾回收,在Java发展以来,由于需要面向对象,而屏蔽掉程序员对于底
2、层的关心,所以在性能上存在很多的缺陷,而通过不断改良,很多缺陷已经逐渐的取消掉了,不过还是依然存在很多的问题,其中最大的一块问题就是JVM的垃圾回收机制,一直以来Java在设计实时系统上都被骂声重重,就是因为垃圾回收存在非常多的问题,世界上目前还没有任何一个垃圾回收机制可以做到无暂停,而只是某些系统可以做到非常少的暂停;本文还不会讨论那么深入的只是,就简单的内部认识做一些概要性的介绍。本文从以下几个方面进行阐述:1、finalize()方法2、System.gc()方法及一些实用方法3、JAVA如何申请内存,和C、C+有何区别4、JVM如何寻找到需要回收的内存5、JVM如何回收内存的(回收算法
3、分解详述)6、应用服务器部署及常用参数设置7、扩展话题JIT(即时编译技术)与lazy evaluation(惰性评估),如何在应用服务器中控制一些必要的信息(小小代码参考)1、finalize()方法: 为了说明JVM回收,不得不先说明一个问题就是关于finalize()方法,所有实体对象都会有这个方法,因为这个Object类定义的,这个可能会被认为是垃圾回收的方法或者叫做析构函数,其实并非如此。finalize在JVM内存会收前会被调用(单并非绝对),而即使不调用它,JVM回收机制通过后面所述的一些算法就可以定位哪些是垃圾内存,那么这个拿来干什么用呢?finalize()其实是要做一些特殊
4、的内存回收操作,如果对JAVA研究稍微多一点,大家会发现JAVA中有一种JNI(Java native interface),这种属于JAVA本地接口调用,即调用本地的其他语言信息,JAVA虚拟机底层掉调用也是这样实现的,这部分调用中可能存在一些对C、C+语言的操作,在C和C+内部通过new、malloc、realloc等关键词创建的对象垃圾回收机制是无能为力的,因为这不是它要管理的范围,而平时这些对象可能被JAVA对应的实体所调用,那么需要在对应JAVA对象放弃时(并不代表回收,只是程序中不使用它了)去调用对应的C、C+提供的本地接口去释放这段内存信息,他们的释放同样需要通过free或del
5、ete去释放,所以我们一般情况下不要滥用finalize(),个人建议是最好不要用,所有非同类语言的调用不一定非要通过JNI来完成的,或者调用完就直接释放掉相应的内容,而不要寄希望于finalize这个方法,因为JVM不保证什么时候会调用这个方法。2、System.gc()或者Runtime.getRuntime().gc();这个可以被认为是强制垃圾回收的一种机制,但是并非强制回收,只是向JVM建议可以进行垃圾回收,而且垃圾回收的地方和多少是不能像C语言一样控制,这是JVM垃圾回收机去控制的。程序中尽量不要是去使用这些东西,除自己开发一些管理代码除外,一般由JVM自己管理即可。这里顺便提及几
6、个查看当前JVM内存的几个简单代码方法(在JVM监控下有很多的工具,而且不同的厂商也有自己不同的工具,不过后续大部分关于java的文章都是只提及到:Hotspot VM的版本,其他的版本可能只是略微说明下):2.1.设置的最大内存:-Xmx等值:(Runtime.getRuntime().maxMemory()/ (1024 * 1024) + MB2.2.当前JVM可使用的内存,这个值初始化和-Xms等值,若加载东西超过这个值,那么以下值会跟着变大,不过上限为-Xmx,由于变动过程中需要将虚拟内存做不断的伸缩过程,所以我们推荐服务器:是-Xms等价于-Xmx的值:(Runtime.getRu
7、ntime().totalMemory()/ (1024 * 1024) + MB2.3.剩余内存,在当前可使用内存基础上,剩余内存等价于其剪掉使用了的内存容量:(Runtime.getRuntime().freeMemory()/ (1024 * 1024) + MB同理如果要查看使用了多少内存或者百分比。可以通过上述几个参数进行运算查看到。顺便在这里提供几个实用方法和类,这部分可能和JVM回收关系不大,不过只是相关推敲,扩展知识面,而且也较为实用的东西:2.4.获取JAVA中的所有系统级属性值(包含虚拟机版本、操作系统、字符集等等信息):System.setProperty(AAA, 12
8、3445);Properties properties = System.getProperties();Enumeration e = properties.keys();while (e.hasMoreElements() String key = (String) e.nextElement();System.out.println(key + = + properties.getProperty(key);2.5.获取系统中所有的环境变量信息:Map env = System.getenv();for (Iterator iterator = env.keySet().iterator
9、(); iterator.hasNext();) String key = iterator.next();System.out.println(key + = + env.get(key);System.out.println(System.getenv(CLASSPATH);2.6.在Win环境下,打开一个记事本和一个WORD文档:try Runtime.getRuntime().exec(notepad); Runtime.getRuntime().exec(cmd /c start Winword);catch(Exception e) e.printStackTrace();2.7.
10、查询当前SERVER下所有的线程信息列表情况(这里需要提供两个步骤,首先要根据任意一个线程获取到顶级线程组的句柄(有关线程的说明,后面专门会有一篇文章说明),然后通过顶级线程组得到其存在线程信息,进行一份拷贝,给与遍历):2.7.1.这里通过当前线程得到顶级线程组信息:public static ThreadGroup getHeadThreadGroup() Thread t = Thread.currentThread();ThreadGroup group = t.getThreadGroup();while(group.getParent() != null) group = grou
11、p.getParent();return group;2.7.2.通过得到的顶级线程组,遍历存在的子元素信息(仅仅遍历常用属性):public static void disAllThread(ThreadGroup threadgroup) Thread list = new Threadthreadgroup.activeCount();threadgroup.enumerate(list);for(Thread thread:list) System.out.println(thread.getId()+/t+thread.getName()+/t+thread.getThreadGro
12、up()+/t +thread.getState()+/t+thread.isAlive();2.7.3.测试方法如:类名.disAllThread(getHeadThreadGroup();即可完成,第一个方法带有不断向上查询的过程,这个过程可能在一般情况下也不会太慢,不过我们最好将其记录在一个地方,方便我们提供管理类来进行直接管理,而不需要每次去获取,对外调用都是封装的运行过程而已。好,回到话题,继续说明JVM垃圾回收机制的信息,下面开始说明JAVA申请内存、回收内存的机制了。3、JAVA如何申请内存,和C、C+有何区别。在上一次缩写的关于JAVA集合类文章中其实已经有部分说明,可以大致看
13、到JAVA内部是按照句柄指向实体的过程,不过这是从JAVA程序设计的角度去理解,如果我们需要更加细致的问一个问题是:JVM垃圾回收机制是如何知道哪些内存是垃圾内存的?JVM为什么不在平时就去回收内存,而是要等到内存不够用的时候才会去回收内存?不得不让我进一步去探讨JAVA是如何细节的申请内存的。从编程思想的角度来说,C、C+new申请的内存也是通过指针指向完成,不过你可以看成是一个地球板块图,在这些板块中,他们去new的过程中,就是好比是找一个版块,因为C、C+在申请内存的过程中,是不断的free和delete操作,所以会产生很多内存的碎片操作,而JAVA不是,JAVA只有内存不够用的时候才会
14、去回收(回收细节讲会在文章后面介绍),也就是说,可以保证内存在一定程度上是连续的。从某种意义上将,只要下一块申请的内存不会到头,就可以继续在上一块申请内存的后面紧跟着去申请内存,那么从某种意义上讲,其申请的开销可能可以和C+媲美。那么JAVA在回收内存后,内存还能是连续的嘛。我们姑且这样去理解,在第五节会说明。继续深入话题:在启动weblogic的时候,如果打开任务管理器,可以马上发现,内存被占用了最少-Xms的大小,一个说明现象就是JVM首先将内存先占用了,然后再分配给其对象的,也就是说我们所谓的new可以理解为在堆上做了一个标记,所以在一定程度上做连续分配内存是可以实现的,只是你会发现若要
15、真正实现连续,必然导致一定程度上的序列化,所以new的开销一般还是蛮大的,即使在后面说的JVM会将内存分成几个大块来完成操作,但是也避免不了序列化的过程。在这里一个小推敲就是,一个SERVER的管理内存范围一般不要太大(一般在12G一个SERVER),推荐也不要太大,因数去考虑:1、JAVA虚拟机回收内存是在不够用的时候再去回收,这个不够用何以说明,很多时候因为计算上的失误导致内存溢出。2、如果一个主机只有2G左右内存,很少的CPU,那么一个JVM也好,但是如果主机很好,如32G内存,那么这样做未必有点过,第一发挥不出来,一个JVM管这么大块内存好像有点过,还有内存不够用去回收这么大块内存(回
16、收内存时一般需暂停服务),需要花时间,第二举个很现实的例子,一个学校如果只有2030人,一个人可以既当校长又当老师,如果一个学校有几百上千人,我想这个人再大的能力忙死也管不过来,而且会出乱子,此时它要请班主任来管了。3、对于大内存来说,使用多个SERVER完成负载均衡,一个暂停服务回收内存,另一个还可以运行嘛。但是JVM是不是真的就不支持大内存了呢?现在你可以这样理解,因为到目前为止可以这样认为,因为世界上所有的java虚拟机,没有不暂停的,而内存越大,回收的时间是必然越长的,不论有多么优秀的算法还做不到“不暂停”的这一点,所以我们的目标是尽量少的暂停,现在的CMS GC已经让我们看到了希望,
17、不过还存在很多的缺陷,我们期待G1的成熟版本的出现,G1的论文很清晰,不过现在还没有一个成熟的版本,所以很期待。4、JVM如何寻找到需要回收的内存:要回收垃圾,那么首先要知道哪些内存是垃圾,或者反过来哪些不是垃圾,这个过程我们一般称为:Mark的过程,Mark过程世界上没有任何一门虚拟机不进行对外暂停。4.1、 引用计数算法:引用计数这里简单说明下,就是当一个引用被赋值的时候,虚拟机将会被知道(部分虚拟机通过写屏障实现),多一个引用,对象的计数增加1,少一个减少1,回收时,只回收等于0的,好处是算法非常简单,而且这种算法由于回收过程中只是看那些没有被引用,所以在一般情况下无需暂停,不过由于它在
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 浅析JAVA之垃圾回收机制 精品资料 浅析 JAVA 垃圾 回收 机制 精品 资料
限制150内