java如何进行内存自动释放,java内存模型和垃圾回收收

深入理解Java垃圾回收机制以及内存泄漏
转载 &更新时间:日 16:43:56 & 投稿:jingxian
下面小编就为大家带来一篇深入理解Java垃圾回收机制以及内存泄漏。小编觉得挺不错的,现在就分享给大家,也给的大家做个参考。一起跟随小编过来看看吧
在segmentfault上看到一个问题:java有完善的GC机制,那么在java中是否会出现内存泄漏的问题,以及能否给出一个内存泄漏的案例。本问题视图给出此问题的完整答案。
垃圾回收机制简介
在程序运行过程中,每创建一个对象都会被分配一定的内存用以存储对象数据。如果只是不停的分配内存,那么程序迟早面临内存不足的问题。所以在任何语言中,都会有一个内存回收机制来释放过期对象的内存,以保证内存能够被重复利用。
内存回收机制按照实现角色的不同可以分为两种,一种是程序员手动实现内存的释放(比如C语言)另一种则是语言内建的内存回收机制比如本文将要介绍的java垃圾回收机制。
Java的垃圾回收机制
在程序的运行时环境中,java虚拟机提供了一个系统级的垃圾回收(GC,Carbage Collection)线程,它负责回收失去引用的对象占用的内存。理解GC的前提是理解一些和垃圾回收相关的概念,下文一一介绍这些概念。
对象在jvm堆区的状态
Java对象的实例存储在jvm的堆区,对于GC线程来说,这些对象有三种状态。
1. 可触及状态:程序中还有变量引用,那么此对象为可触及状态。
2. 可复活状态:当程序中已经没有变量引用这个对象,那么此对象由可触及状态转为可复活状态。CG线程将在一定的时间准备调用此对象的finalize方法(finalize方法继承或重写子Object),finalize方法内的代码有可能将对象转为可触及状态,否则对象转化为不可触及状态。
3. 不可触及状态:只有当对象处于不可触及状态时,GC线程才能回收此对象的内存。
GC为了能够正确释放对象,必须监控每一个对象的运行状态,包括对象的申请、引用、被引用、赋值等,GC都需要进行监控,所以无论一个对象处于上文中的任何状态GC都会知道。
上文说到,GC线程会在一定的时间执行可复活状态对象的finalize方法,那么何时执行呢?由于不同的JVM实现者可能使用不同的算法管理GC,所以在任何时候,开发者无法预料GC线程进行各项操作(包括检测对象状态、释放对象内存、调用对象的finalize方法)的时机。虽然可以通过System.gc()和Runtime.gc()函数提醒GC线程尽快进行垃圾回收操作,但是这也无法保证GC线程马上就会进行相应的回收操作。
内存泄漏指由于错误的设计造成程序未能释放已经不再使用的内存,造成资源浪费。GC会自动清理失去引用的对象所占用的内存。但是,由于程序设计错误而导致某些对象始终被引用,那么将会出现内存泄漏。
比如下面的例子。使用数组实现了一个栈,有入栈和出栈两个操作。
import com.sun.javafx.collections.ElementObservableListD
import com.sun.swing.internal.plaf.metal.resources.metal_
import java.beans.ExceptionL
import java.util.EmptyStackE
* Created by peng on 14-9-21.
public class MyStack {
private Object[]
private int Increment = 10;
private int size = 0;
public MyStack(int size) {
elements = new Object[size];
public void push(Object o) {
capacity();
elements[size++] =
public Object pop() {
if (size == 0)
throw new EmptyStackException();
return elements[--size];
//增加栈的容量
private void capacity() {
if (elements.length != size)
Object[] newArray = new Object[elements.length + Increment];
System.arraycopy(elements, 0, newArray, 0, size);
public static void main(String[] args) {
MyStack stack = new MyStack(100);
for (int i = 0; i & 100; i++)
stack.push(new Integer(i));
for (int i = 0; i & 100; i++) {
System.out.println(stack.pop().toString());
这个程序是可用的,支持常用的入栈和出栈操作。但是,有一个问题没有处理好,就是当出栈操作的时候,并没有释放数组中出栈元素的引用,这导致程序将一直保持对这个Object的引用(此object由数组引用),GC永远认为此对象是可触及的,也就更加谈不上释放其内存了。这就是内存泄漏的一个典型案例。针对此,修改后的代码为:
public Object pop() {
if (size == 0)
throw new EmptyStackException();
Object o = elements[--size];
elements[size] =
以上这篇深入理解Java垃圾回收机制以及内存泄漏就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持脚本之家。
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具java是不是内存耗尽时,才执行垃圾回收装置_百度知道
java是不是内存耗尽时,才执行垃圾回收装置
答题抽奖
首次认真答题后
即可获得3次抽奖机会,100%中奖。
采纳数:107
获赞数:87
不是的,如果内存耗尽才回收的话,计算机早都崩溃了。java是有垃圾回收机制(GC),有守护进程一直在监控java分配的内存资源,当有资源或者对象不再被使用或者使用完成后,java会销毁该内存对象,释放内存资源。
为你推荐:
其他类似问题
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。JAVA中的变量如何释放内存
[问题点数:25分]
本版专家分:0
CSDN今日推荐
本版专家分:10515
本版专家分:543
本版专家分:10
本版专家分:0
本版专家分:1758
本版专家分:37619
2009年11月 Java大版内专家分月排行榜第一
2010年2月 Java大版内专家分月排行榜第二
2011年7月 Java大版内专家分月排行榜第三2010年1月 Java大版内专家分月排行榜第三2009年12月 Java大版内专家分月排行榜第三
本版专家分:1841
本版专家分:1174
本版专家分:1272
本版专家分:416
本版专家分:57683
2011年12月 Java大版内专家分月排行榜第二2011年11月 Java大版内专家分月排行榜第二2010年9月 Java大版内专家分月排行榜第二
2011年10月 Java大版内专家分月排行榜第三
本版专家分:1037
匿名用户不能发表回复!
其他相关推荐关于JAVA程序内存释放的问题
<a data-traceid="question_detail_above_text_l&&
问大家一个问题,JAVA内存释放到底怎么弄的,说是GC自动回收,可我感觉它压根就没干活,我这里举个例子:
比如我一个程序,线程间隔执行,第一次加载了10MB的数据,在该数据处理完成后设置所有关联该数据的对象为NULL,按理说隔一段时间内存应该会下降,我盯着任务管理器看了大概五分钟左右,下降了约100K,这不是坑爹么?& 而且每次加载大数据内存都会上涨但处理完后跌幅都很小,内存持续上涨到一个顶峰后会稳定下来,但加载数据大于这个顶峰还是会继续上涨,这是个什么情况?
我这里做个推测:JAVA程序的内存占用是不断的扩容,但不立马释放占用内存(就算置NULL也一样),当下次有大数据加载时,直接使用第一次申请的内存来存储,如果不够就继续扩容,直至扩展到最大上限。不知道是否正确?
还有一个问题,finalize方法也不是每次都会调用,我记得某本书里边明确的写着“虚拟机至少保证调用该对象的finalize一次,但不确定什么时候调用”,经过测试感觉完全被坑了。
经过总结感觉JAVA的的垃圾回收和内存回收是两码事,不知道各位是怎么处理内存回收的?
java内存是JVM到了内存不够用的时候才会去清理内存的,如果内存够用那么可能就是继续新内存开下去了。那些垃圾内存也在哪里。所以垃圾回收就是一个不靠谱的东西,不太容易精确控制,实际上也不要试图去控制,否则得不偿失。垃圾回收不靠谱,finalize什么时候调用也是不靠谱的,但是这是个遗书,他肯定会给你死之前一个写遗书的机会,只不过不能确定这个时刻。
--- 共有 4 条评论 ---
: jvm的内存有效使用率越高的时候,垃圾回收越多,程序运行越吃力。jvm内存有效率低的时候,垃圾回收越懒惰,程序运行更快。
在压力测试的情况下,回收就很明显了
:http://www.oschina.net/question/29
感觉JAVA对象占用的内存会清理掉,因为还是有时不时的下降个几百KB的,但数据占用的内存一直居高不下,这点很悲催啊。而且finalize方法不是总是调用,我设置该对象为NULL,然后等了五分钟还没看到调用。
设个内存上限试试呢
我做了下测试,开启一个线程,暂停时间为3秒钟,每次执行申请一块100MB的byte数组空间,经过测试,在每次销毁后调用System.gc()会出现间隔规律的内存起伏变化,但不掉用System.gc()则一直居高不下。附图:
这个是执行线程时的内存。
这个则是调用System.gc()后的内存。
看来gc调用还是有些用处的。
--- 共有 7 条评论 ---
: 哈哈,这样如果程序员乱用的话,风险也忒大了,会动不动就挂的。。。哈哈
: 嗯。gc频繁会影响系统性能。
: 嗯,确实是这样,我不需要立即执行,只要执行就好,总比在溢出前才调用要来的强。一个程序总占用三四百兆消耗太大了。
: 前两年好像王八壳说要出商业版的JDK,听说其中一个功能就是可以手动垃圾回收。。。
: System.gc()不是立即执行回收任务,只是告诉jvm有东西需要回收,但是到底什么时候回收,还是要等待jvm调度的。
JVM运行参数里面增加一个 &-verbose:gc 和 -XX:+PrintGcDetails 在控制台看一下垃圾回收现成的执行细节就知道了。
对象回收和回收JVM进程占用的本来就不是一个概念,你总不能每次回收完对象就把内存全部还给操作系统,以后每次new新对象又找操作系统要内存,这就没效率了。要查看java程序的内存使用情况,最好是使用jstat命令。
finalize不会保证执行的,对象回收的时候,如果判定finalize需要执行,就会把对象放到一个队列里面,由另外一个低优先级的线程去执行,但是是允许gc线程不用等到finalize执行就直接回收它的。另外如果一个对象的finalize执行过,并且成功的让自己重新被强引用引用到,他可以不被回收。但第二次再准备回收他时,他就不会再有finalize的执行机会了。
--- 共有 4 条评论 ---
: 也没这么严重了。高压情况下,除了优化配置,也就只能分机器了。
: 字节码以上是一层、虚拟机规范是一层,虚拟机具体实现又是一层。谁说JAVA好开发? 很多问题不懂底层的高层压根就解决不了。
: 我以前看书的时候,也是说这东西就和C++的析构函数一样,回收前就执行的。但是一直不明白书上也一直不建议用这玩意儿。要搞明白,也只能看一些解析JVM的书,和JVM源码了。国产的语法书确实够害人的。
看到书上是这么写的,但和实际情况还是不一样,算是学到了吧。 谢谢你的回复!
首先,在JVM中的GC不是一有垃圾就会调用的,调用GC的时间是不可预期的,大概是在内存不够分配的时候才会调用,但也许是在这之前。
其次,关于finalize()方法,在对象堆中,失去引用的对象(准确的说是在根搜索算法判定为不可达的对象)到被GC清除,至少要经历两个过程。第一,他们会首先被虚拟机作一次标记,判断有没有必要执行finalize()方法。如果该对象没有重写finalize()方法或者之前调用过finalize()方法,那么会被判定为没有必要调用finalize()方法。稍后,被判定为有必要执行finalize()方法的对象,会由虚拟机自动建立的一个低优先级线程去执行这些对象的finalize()方法。但不保证会等待该方法结束。什么原因自己想想也知道。& 正如前面有人说过,finalize()方法,只是对象的一个遗书。&这个方法调用之后,如果该对象仍然没有任何对它的引用。那么它便离死不远了。 其实在执行finalize()的时候,对象可以重新建立引用。
试试这段代码:
public class GCDemo {
public static GCDemo instance=
protected void finalize() throws Throwable {
// TODO Auto-generated method stub
super.finalize();
System.out.println(&finalize method execute!&);
public static void isAlive()
if(null!=instance)
System.out.println(&I'm still alive!&);
System.out.print(&oh I'm dead!&);
public static void main(String[] args) {
instance=new GCDemo();
//第一次失去引用
System.gc();
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
isAlive();
**************************第二次失去引用
System.gc();
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
isAlive();
&&&&&&&&&&&&
可以看到System.GC之后,垃圾不会马上清理的。
--- 共有 1 条评论 ---
这些概念都懂,可遇到实际情况光靠这些解决不了问题,往往问题解决了回过头来再看才发现确实是那么回事。 在复杂的程序结构中,肯定不能让虚拟机自动判断内存是否不够才gc的,一个服务器不仅跑一个程序,内存占用太大不是什么好现象。现在确保gc调用有效(虽然不一定及时)就可以了。谢谢!
上面代码的运行结果:
finalize method execute! I'm still alive! oh I'm dead!
楼主竟然用进程管理器看java的内存,我汗了。这个内存是整个虚拟机爬起来用的内存,不只是你的程序所用的内存,如果你改一下配置这个内存一起来就大的吓到你。gc除非是蛋疼的情况下,否则不要用代码去掉用gc,这个玩意就是通知虚拟机把java程序挂起,开始大扫除。这玩意调用了大多数时候是适得其反。甚至gc会导致jvm运行状态更加恶化。
对于楼上的楼上那个代码,gc之后会被立刻清理,finalize是一个遗书,但是还有一个值得注意的地方,你可以再这个方法里复活,很明显你的代码就是如此,让他复活了。实际上正是系统gc起作用了,才导致你的有复活的机会。
此外还有一个很重要的地方,对于任何给定对象,Java 虚拟机最多只调用一次 finalize 方法。也就是说只给你一次反悔的机会,否则这种复活的代码就是耍赖了,就会导致对象永远清理不掉。这也是第二gc之后直接死掉的原因,因为这一次复活技能已经使用过了。
--- 共有 4 条评论 ---
: 专业的分析当然需要专业的工具,我这里就临时凑合下啦 哈哈
: 真正要分析java程序内存,要用分析工具,否则你在这里看到的内存绝多数情况下都是一个忽悠你的数值。
我现在首要的目标就是让程序内存占用降下来,然后再平衡性能。 不知道大家写完程序后有没有进行过几个月的内存涨幅观测,随着运行的时间变长内存肯定是越来越大的(jvm默认配置情况下),这里肯定要设置一个上限来清理或管理,否则一般服务器真的扛不住,要长年累月运行必须考虑这个啊。
呵呵,最方便的还是任务管理器,启动程序时是虚拟机进程内存,我是看线程启动时的涨幅,任务管理器完全可以胜任。
java程序运行时间越长用的内存就会更多,这是很普通的现象。特别是现在很多人用喜欢用设置大内存给虚拟机,动不动就是最大值几个G过去了。如果一个程序在300M内存就可以满足基本需求的时候,给你了他3G,那么java这个进程的使用数量,很可能飙升到2G,而且这个时候很可能你的程序根本就没有操作。这个过程就是jvm懒惰的垃圾回收造成的,你给越大内存,那么他就用的越多,垃圾回收就越是不启动。但是如果你把内存最大值限制在500M那么你就会看到这个程序机会一直稳定在一个合理的位置。
但是这容易形成一个恶性循环,程序员容易用大内存掩盖自己程序的不足,典型的就是静态变量存东西,随着时间长越来越大,内存越来越多,而这个时候往往怀疑jvm,所以继续加大内存,反而掩盖自己的错误。如果要看java程序内存只能用分析器,分析器作为一个额外的东西他会导致jvm更多的启动垃圾回收,这个时候看到的内存才是真正jvm的内存。
--- 共有 3 条评论 ---
不知道你说的是什么意思,占用内存又能怎么样呢?关键是要看是否有真正的问题!而且32位的java最多只能给不到2G内存吧?
: 如果想要知道问题就要缩小内存,只给他一个刚刚能够正常运行的数量,如果最容易发现java程序自身的不足。
内存占用太大我第一个想到的就是是否内存泄漏,等能完全控制住内存的涨跌占用了再扩大内存,不然挂了都不知道哪里的问题。就像你说的,问题全部推给虚拟机。
用jconsole可以很清楚的看到JVM对内存的释放。
--- 共有 1 条评论 ---
用过这工具,感觉太专业了,看的我头晕,还得对java内存区域有了解,什么新生代老年代永久代也得要清楚。做个验证嘛,用这工具就感觉大炮打蚊子,呵呵。
JAVA中内存回收基本是不受你个人控制的,这一定程度上也提高了java的效率。所以说你不要纠结于这个,没有内存泄漏就好了。JVM有自己的一套机制,会在内存比较稀缺的时候进行GC处理。
--- 共有 2 条评论 ---
真正想了解其原理,还是应该从官方渠道和通过一些专业工具实施。你这样做给人感觉不会有什么结论,也没有给自己或他人带来什么知识。
不纠结这个永远不知道居高不下的内存是JVM正常占用还是内存泄漏,能控制下就控制下,不然莫名其妙的问题很让人头疼。部分内容转自:http://blog.csdn.net/zsuguangh/article/details/6429592
怎样减少GC开销的?
  (1)不要显式调用System.gc()
  此函数建议JVM进行主GC,虽然只是建议而非一定,但很多情况下它会触发主GC,从而增加主GC的频率,也即增加了间歇性停顿的次数。
  (2)尽量减少临时对象的使用
  临时对象在跳出函数调用后,会成为垃圾,少用临时变量就相当于减少了垃圾的产生,从而延长了出现上述第二个触发条件出现的时间,减少了主GC的机会。
  (3)对象不用时最好显式置为Null
  一般而言,为Null的对象都会被作为垃圾处理,所以将不用的对象显式地设为Null,有利于GC收集器判定垃圾,从而提高了GC的效率。
  (4)尽量使用StringBuffer,而不用String来累加字符串
  由于String是固定长的字符串对象,累加String对象时,并非在一个String对象中扩增,而是重新创建新的String对象,如Str5=Str1+Str2+Str3+Str4,这条语句执行过程中会产生多个垃圾对象,因为对次作“+”操作时都必须创建新的String对象,但这些过渡对象对系统来说是没有实际意义的,只会增加更多的垃圾。避免这种情况可以改用StringBuffer来累加字符串,因StringBuffer是可变长的,它在原有基础上进行扩增,不会产生中间对象。
  (5)能用基本类型如Int,Long,就不用Integer,Long对象
  基本类型变量占用的内存资源比相应对象占用的少得多,如果没有必要,最好使用基本变量。
  (6)尽量少用静态对象变量
  静态变量属于全局变量,不会被GC回收,它们会一直占用内存。
  (7)分散对象创建或删除的时间
  集中在短时间内大量创建新对象,特别是大对象,会导致突然需要大量内存,JVM在面临这种情况时,只能进行主GC,以回收内存或整合内存碎片,从而增加主GC的频率。集中删除对象,道理也是一样的。它使得突然出现了大量的垃圾对象,空闲空间必然减少,从而大大增加了下一次创建新对象时强制主GC的机会。
减少GC开销的5个编码技巧
没有更多推荐了,}

我要回帖

更多关于 java有垃圾回收机制,内存回收 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信