java的内存回收机制_JAVA内存垃圾回收机制 | 学步园

. 什么是内存垃圾,哪些内存符合垃圾的标准我们在前面讲过了,堆是一个"运行时"数据区,是通过"new"等指令建立的,Java 的堆是由Java 的垃圾回收机制来负责处理的,堆是动态分配内存大小,垃圾收集器可以自动回收不再使用的内存空间。也就是说,所谓的"内存垃圾"是指在堆上开辟的内存空间在不用的时候就变成了"垃圾"。C++或其他程序设计语言中,必须由程序员自行声明产生和回收,否则其中的资源将消耗,造成资源的浪费甚至死机。但手工回收内存往往是一项复杂而艰巨的工作。因为要预先确定占用的内存空间是否应该被回收是非常困难的!如果一段程序不能回收内存空间,而且在程序运行时系统中又没有了可以分配的内存空间时,这段程序就只能崩溃。Java 和C++相比的优势在于,这部分"垃圾"可以被Java 虚拟机(JVM)中的一个程序发现并自动清除掉,而不用程序员自己想着"delete"了。Java 语言提供了一个系统级的线程,即垃圾收集器线程( Garbage CollectionThread),来跟踪每一块分配出去的内存空间,当JVM 处于空闲循环时,自动回收每一块可以回收的内存。1.1 垃圾回收工作机制垃圾收集器线程它是一种低优先级的线程,它必须在一个Java 程序的运行过程中出现内存空闲的时候才去进行回收处理。垃圾收集器系统有其判断内存块是否需要回收的判断标准的。垃圾收集器完全是自动被执行的,它不能被强制执行,即使程序员能明确地判断出某一块内存应该被回收了,也不能强制执行垃圾回收程序进行垃圾回收。程序员可以做的只有调用"System.gc()"来"建议"执行垃圾收集器程序,但是这个垃圾收集程序什么时候被执行以及是否被执行了,都是不不能控制的。但是虽然垃圾收集器是低优先级的线程,却在系统内存可用量过低时,它仍然可能会突发地执行来挽救系统。1.2 哪些符合"垃圾"标准如果想了解JVM 的垃圾回收,就必须要知道JVM 垃圾回收的标准。垃圾收集器的"垃圾"标准:对象已经不能被程序中的其他程序所引用的时候,那么这个对象的内存空间已经没有用了。比如当一个方法执行完毕时,在这个方法中声明的对象就超出其声明周期,这时候就可以被当作垃圾收集了,只有当这个方法被再次被调用时才会被重新创建。例如:另外还可以将对象的引用变量初始化为null 值,也可以来暗示垃圾收集器来收集该对象。例如:1.3 finalize()在该对象垃圾回收前调用垃圾收集器跟踪每一个对象,把那些不可到达的对象占有的内存空间收集起来,并且在每次进行垃圾收集之前,垃圾收集器都会调用一下finalize()方法。Java 语言允许程序员给任何对象添加finalize( )方法,但也不能过分依赖该方法对系统资源的回收和再利用,因为这个方法调用后的执行结果是不可预知的。对于任何给定对象,Java 虚拟机最多只调用一次finalize 方法。我们用这个程序来演示一下:……public void function(){OBJ obj=new OBJ();……}…………OBJ obj=new OBJ();Obj=null;……我们在命令行中键入如下命令:这时候,我们将JVM 所许可使用的最大内存设置成"1k",当内存被占满前JVM 会首先去进行public class finalizeTest{public static void main( String[] args ){finalizeTest ft=new finalizeTest();ft.loading();byte bs[]=new byte[1450000];}public void loading(){test t=new test();t.callme();}}class test{protected void finalize(){System.out.println("call finalize");}public void callme(){System.out.println("callme");}}java -Xmx1k finalizeTest内存回收,于是失去活动的"test"对象被回收,在回收前调用了"finalize()"。2. JVM 垃圾回收的相关知识JVM 使用的是分代垃圾回收的方式,主要是因为在程序运行的时候会有如下特点:大多数对象在创建后很快就没有对象使用它了。大多数在一直被使用的对象很少再去引用新创建的对象。因此就将Java 对象分为"年轻"对象和"年老"对象,JVM 将内存堆(Heap)分为两个区域,一个是"年轻"区,另一个是"老"区,Java 将这两个区域分别称作是"新生代"和"老生代"。"新生代"区域中,绝大多数新创建的对象都存放在这个区域里,此区域一般来说较小而且垃圾回收频率较高,同时因为"新生代"采用的回收的效率也非常高。而"老生代"区域中存放的是在"新生代"中生存了较长时间的对象,这些对象将被转移到"老生代"区。这个区域一般要大一些而且增长的速度相对于"新生代"要慢一些,"老生代"垃圾回收的执行频率也会低很多。由于JVM 在垃圾回收处理时会消耗一定的系统资源,因此有时候通过JVM 启动的时候添加相关参数来控制"新生代"区域的大小,来调整垃圾回收处理的频率非常有用。以便于我们更合理的利用系统资源。"新生代"区域设置参数是"-Xmn",用这个参数可以制定"新生代"区域的大小。我们来举一个例子说明:我们就用系统自带的程序作为例子,在命令行上键入如下指令:上面加入了一个新的参数"XX:+PrintGCDetails",这个参数能够打印出GC 的详细信息。屏幕输出如下(节选):CD C:/java/demo/jfc/SwingSet2[回车]C:/java/demo/jfc/SwingSet2>java -jar -verbose:gc-Xmn4m XX:+PrintGCDetails SwingSet2.jar[回车]我们需要解释一下输出的详细内容的意思,拿第一行输出来说:"DefNew: 3469K->84K(3712K), 0.0007778 secs"是指"新生代"的垃圾回收情况,这里的意思是从占用3469K 内存空间变为84K 内存空间,用时0.0007778秒。"23035K->19679K(28728K), 0.0009191 secs"是指总体GC 的回收情况,整体堆空间占用从23035K 降低到19679K 的水平,用时0.0009191秒。那么,这时候我们在将"新生代"的内存设为8M,并把堆的最大可控值设定为32M,再去执行,键入如下指令:得到的结果如下(节选):这个结果说明:[GC [DefNew: 3469K->84K(3712K), 0.0007778 secs]23035K->19679K(28728K), 0.0009191 secs][GC [DefNew: 3284K->171K(3712K), 0.0007283 secs]22878K->19766K(28728K), 0.0008669 secs][GC [DefNew: 3476K->260K(3712K), 0.0008504 secs]23071K->19855K(28728K), 0.0009862 secs][GC [DefNew: 3502K->87K(3712K), 0.0009267 secs]23096K->19682K(28728K), 0.0010610 secs]java -jar -verbose:gc -Xmn8m -Xmx32mXX:+PrintGCDetails SwingSet2.jar[回车][GC [DefNew: 6633K->6633K(7424K), 0.0000684 secs][Tenured: 18740K->18820K(24576K), 0.0636505 secs]25374K->18820K(32000K), 0.0639274 secs][GC [DefNew: 6646K->6646K(7424K), 0.0002581 secs][Tenured: 18820K->18884K(24576K), 0.0651957 secs]25467K->18884K(32000K), 0.0658804 secs][GC [DefNew: 6611K->6611K(7424K), 0.0000668 secs][Tenured: 18884K->18505K(24576K), 0.0931406 secs]25496K->18505K(32000K), 0.0934295 secs]"[DefNew: 6633K->6633K(7424K), 0.0000684 secs]"是指"新生代"的垃圾回收情况,这里的意思是从占用6633K 内存空间变为6633K 内存空间,用时0. 0000684秒。"25374K->18820K(32000K), 0.0639274 secs"是指总体GC 的回收情况,整体堆空间占用从25374K 降低到18820K 的水平,用时0. 0639274秒。"[Tenured: 18740K->18820K(24576K), 0.0636505 secs]"是指"老生代"GC 的回收情况,整体堆空间占用从18740K 降低到18820K 的水平,用时0.0009012秒。通过这些参数的调整我们可以看到在处理垃圾收集问题时,从垃圾回收的频率是时间方面的变化,我们可以根据不同程序的不同情况予以调整。最后有必要提一下GC 的相关参数:-XX:+PrintGCDetails 显示GC 的详细信息-XX:+PrintGCApplicationConcurrentTime 打印应用执行的时间-XX:+PrintGCApplicationStoppedTime 打印应用被暂停的时间注:":"后的"+"号表示开启此选项,如果是"-"号那么表示关闭此选项。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java2D 是 Java 平台提供的一个 2D 图形 API,可以用来创建各种图形、绘制图像、处理颜色、应用纹理等等。下面是一个简单的例子,展示如何使用 Java2D 创建一个简单的图形。 ```java import java.awt.Color; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Rectangle; import javax.swing.JFrame; import javax.swing.JPanel; public class MyPanel extends JPanel { public void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g; // 设置背景颜色 g2d.setBackground(Color.WHITE); // 设置画笔颜色 g2d.setColor(Color.BLACK); // 创建一个矩形 Rectangle rect = new Rectangle(50, 50, 100, 100); // 填充矩形 g2d.fill(rect); } public static void main(String[] args) { JFrame frame = new JFrame("Java2D Example"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(200, 200); MyPanel panel = new MyPanel(); frame.add(panel); frame.setVisible(true); } } ``` 在上面的代码中,我们继承了 JPanel 类,并重写了它的 paintComponent 方法。在该方法中,我们首先调用了父类的 paintComponent 方法,然后获取 Graphics2D 对象,设置了背景颜色和画笔颜色,并创建了一个矩形,最后使用 fill 方法填充矩形。 在 main 方法中,我们创建了一个 JFrame 对象,设置了标题和大小,创建了一个 MyPanel 对象,并将它添加到 JFrame 中,最后设置 JFrame 可见。运行程序,你会看到一个黑色的矩形在白色的背景上。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值