`
cary
  • 浏览: 84275 次
  • 性别: Icon_minigender_1
  • 来自: 合肥
社区版块
存档分类
最新评论

关于GC垃圾回收〔网络整理,并非原创〕

    博客分类:
  • J2EE
阅读更多
JVM配置参数中文说明:
-----------------------------------------------------------------------
1、-Xmixed           mixed mode execution (default)
混合模式执行

2、-Xint             interpreted mode execution only
解释模式执行

3、-Xbootclasspath:<directories and zip/jar files separated by ;>
      set search path for bootstrap classes and resources
设置zip/jar资源或者类(.class文件)存放目录路径

3、-Xbootclasspath/a:<directories and zip/jar files separated by ;>
      append to end of bootstrap class path
追加zip/jar资源或者类(.class文件)存放目录路径

4、-Xbootclasspath/p:<directories and zip/jar files separated by ;>
      prepend in front of bootstrap class path
预先加载zip/jar资源或者类(.class文件)存放目录路径

5、-Xnoclassgc       disable class garbage collection
关闭类垃圾回收功能

6、-Xincgc           enable incremental garbage collection
开启类的垃圾回收功能

7、-Xloggc:<file>    log GC status to a file with time stamps
记录垃圾回日志到一个文件。

8、-Xbatch           disable background compilation
关闭后台编译

9、-Xms<size>        set initial Java heap size
设置JVM初始化堆内存大小

10、-Xmx<size>        set maximum Java heap size
设置JVM最大的堆内存大小

11、-Xss<size>        set java thread stack size
设置JVM栈内存大小

12、-Xprof            output cpu profiling data
输入CPU概要表数据

13、-Xfuture          enable strictest checks, anticipating future default
执行严格的代码检查,预测可能出现的情况

14、-Xrs              reduce use of OS signals by Java/VM (see documentation)
通过JVM还原操作系统信号

15、-Xcheck:jni       perform additional checks for JNI functions
对JNI函数执行检查

16、-Xshare:off       do not attempt to use shared class data
尽可能不去使用共享类的数据

17、-Xshare:auto      use shared class data if possible (default)
尽可能的使用共享类的数据

18、-Xshare:on       require using shared class data, otherwise fail.
尽可能的使用共享类的数据,否则运行失败

The -X options are non-standard and subject to change without notice.


管理内存查看可HEAP的查看可以利用JPROFILE来跟踪其变化,以达到找到其性能的瓶颈处

深入观察GC
我们要计算的统计如下所示“
● 考虑的运行的持续时间
● 收集总数
● 收集频率
● 收集所用最长时间
● 收集所用总时间
● 收集所用平均时间
● 收集的平均间隔
● 分配的字节总数
● 每次收集每秒分配的字节数
● 恢复的字节总数
● 每次收集每秒恢复的字节总数

Sun 1.4.2_03 JVM 以 -Xloggc:filename 运行默认的标记-清除收集器所生成的日志记录
要让垃圾收集(GC)回收程序不再使用的对象,对象的逻辑生命周期(应用程序使用它的时间)和对象拥有的引用的实际生命周期必须是相同的。在大多数时候,好的软件工程技术保证这是自动实现的,不用我们对对象生命周期问题花费过多心思。但是偶尔我们会创建一个引用,它在内存中包含对象的时间比我们预期的要长得多,这种情况称无意识的对象保留(unintentional object retention)

全局MAP造成的内存泄漏
无意识对象(unintentional object retention)保留最常见的原因是使用MAP将元数据与临时对象(transient object)相关联。假定一个对象具有中等生命周期,比分配它的那个方法调用的生命周期长,但是比应用程序的生命周期短,如客户机的套接字连接。需要将一些元数据与这个套接字关联,如生成连接的用户的标示。在创建SOCKET时是不知道这些信息的,并且不能将数据添加到SOCKET对象上,因为不能控制SOCKET类或者它的子类。这时,典型的方法是在一个全局MAP中存储这些信息。如SocketManager类所示:
Public class SocketManager{
Private Map<Socket,User> m = new HashMap<Socket,User>();

Public void setUser(Socket s,User s)
{
m.put(s,u);
}
Public User getUser(Socket s)
{
Return m.get(s);
}

Public void removeUser(Socket s)
{
m.remove(s);
}
}

SocketManager socketManager;
………
socketManager.setUser(socket,user);
这种方法的问题是元数据的生命周期需要与套接字的生命挂钩,但是除非准确地知道什么时候程序不在需要这个套接字,并记住从MAP中删除相应的映射,否则,SOCKET和USER对象将会永远保留在MAP中,远远超过响应了请求和关闭套接字的时间。这是阻止SOCKET和USER对象被垃圾收集,即使应用程序不会再使用它们。这些对象留下来不受控制,很容易造成程序在长时间运行后内存爆满。除了最简单的情况,在几乎所有情况下找出什么时候SOCKET不再被程序使用是一件很烦人和容易出错的任务,需要人工对内存进行管理。

找出内存泄漏
程序有内存泄漏的第一个迹象通常是它抛出一个OutOfMemoryError,或者因为频繁的垃圾收集而表现出糟糕的性能。幸运的是,垃圾收集可以提供能够用来诊断内存泄漏的大量信息。如果以-verbose:gc或者-Xloggc选项调用JVM,那么每次GC运行时在控制台上或者日志文件中会打印出一个诊断信息,包括它所花费的时间,当前堆使用情况以及恢复了多少内存。纪录GC使用情况并不具体有干扰性,因此如果需要分析内存问题或者调优垃圾收集器,在生产环境中默认启用GC日志是值得的。
有工具可以利用GC日志输出并以图形的方式将它显示出来,Jtune就是这样的一种工具。观察GC之后堆大小的图,可以看到程序内存使用的驱使。对于大多数程序来说,可以将内存使用分为两部:baseline使用和 current load使用。对于服务器应用程序,baseline使用就是应用程序在没有任何负荷、但是已经准备好接受请求时的内存使用,current load使用是在处理请求过程中使用的、但是在请求处理完成后会释放的内存。只要内存大体上是恒定的,应用程序通常会很快达到一个稳定的内存使用水平。如果在应用程序已经使用了其初始化并且负荷没有增加的情况下,内存使用持续增加,那么程序就可能在处理前面的请求时保留了生成的对象。

下面代码是基于MAP的内存泄漏的程序

Public class MapLeaker
{
Public ExecutorService exec = Executors.newFixedThreadPool(5);
Public Map<Task,TaskStatus> taskStatus = Collections.synchronizedMap(new HashMap<Task,TaskStatus>());
Private Random random = new Random();

Private enum TaskStatus{NOT_STARTED,STARTED,FINISHED};

Private class Task implements Runnable
{
Private int[] numbers = new int[random.nexInt(200)];

Public void run()
{
Int[] temp = new int[random.nexInt(1000)];
taskStatus.put(this,TaskStatus.STARTED);
doSomeWork();
taskStatus.put(this,TaskStatus.FINISHED);
}
}

Public Task newtTask()
{
Task t = new Task();
taskStatus.put(t,TaskStatus.NOT_STARRED);
return t;
}
}
上述程序确信存在内存泄漏后,内制的hprof工具也可完成这项工作。要使用hprof并让它跟踪内存使用,需要以-Xrunhprof.heap = sites 选项调用JVM.


编写对GC友好,又不泄漏的代码
1:使用更多生命周期短的,小的,不改变指向(immutable)的对象,编写清晰的代码。
出于懒惰也好,朴素的节俭意识也好,我们都习惯对一个变量重用在重用。但是…..
JAVA的垃圾收集器喜欢短生命周期的对象,对象如果在新生代内,在垃圾收集发生前死掉了,垃圾收集器就什么都不用做了。
频繁的NEW对象也导致更频繁的GC。大对象的分配效率更底,而且对非压缩算法的垃圾收集器,更容易造成碎片。
对象重用增加代码的复杂度,降低了可读性。所以呼吁,比如不要害怕为中间结果分配小对象。
2:将用完的对象设为NULL其实没什么作用
貌似很酷的把对象主动设为NULL的“好习惯”其实没什么用。JIT Compiler会自动分析LOCAL变量的生命周期。
只有一个例外情况,就是String[1024] foo 这种赤裸裸的数组。你需要主动的FOO[100]=NULL释放第100号元素,所以最好还是直接用ArrayList这些标准库算了。
3:避免显示GS-System.gc().
大家都知道System.gc()不好,full-gc浪费巨大,gc的时机把握不一定对等等,甚至-XX:+DisableExplicitGC的JVM参数来禁止它。
先用FindBugs 查一下所用到的全部第三方类库吧...
至少RMI 就会老实不客气的执行System.gc()来实现分布式GC算法。但我也不会用RMI啊。那EJB呢,EJB可是建在RMI上的。
如果无可避免,用-Dsun.rmi.dgc.client.gcInterval=3600000 -Dsun.rmi.dgc.server.gcInterval=3600000 (单位为微妙) 增大大GC的间隔(原默认值为1分钟),-XX:+ExplicitGCInvokesConcurrent 让System.gc() 也CMS并发执行。
4.继续千夫所指的finalize()

    大家也都知道finalize()不好,分配代价昂贵,释放代价更昂贵(要多走一个循环,而且他们死得慢,和他们相关联的对象也跟着死得慢了),又不确定能否被调用(JVM开始关闭时,就不会再进行垃圾收集),又不确定何时被调用(GC时间不定,即使system.gc()也只是提醒而不是强迫GC,又不确定以什么样的顺序调用,所以finalize不是C++的析构函数,也不像C++的析构函数。

   我们都知道啊,所以我从来都没使用。都是在显式的维护那些外部资源,比如在finally{}里释放。

5.WeakReference/SoftReference

   这是个平时不怎么会搭理,偶然知道了又觉得有用的Java特征。大家都知道Java里所有对象除int等基本类型外,都是Pass by Reference的指针,实例只要被一个对象连着,就不会被收集。
    而WeakReference就是真正意义上的C++指针,只是单纯的指向一个对象,而不会影响对象的引用计数。
    而SoftReference更特别,在内存足够时,对象会因为SoftReference的存在而不被收集,但内存不足时,对象就还是会被收集,怎么看都是做简单缓存的料子。代码如下:



  Foo foo = new Foo();
  SoftReference sr= new SoftReference(foo);
  Foo bar =  sr.get();
  如果foo已被垃圾收集,sr.get()会返回Null;

  另外还有一个ReferenceQueue的机制,使得对象被回收时能获得通知,比finalize()完全不知道GC何时会执行要聪明的多。



  ReferenceQueue rq = new ReferenceQueue();
  ref = new WeakReference(foo, rq);
  WeakReference cleaned = rq.pool();

  cleaned就是刚刚被GC掉的WeakReference。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics