电话+V:192606-48052 ,欢迎咨询java的垃圾回收由程序员进行的吗,[python实用课程],[C++单片机原理],[C#网站搭建],[Nodejs小程序开发],[ios游戏开发],[安卓游戏开发],[教会用大脑用想法赚钱实现阶层跨越]
Java不需要程序员直接控制回收内存(不同于C和C++),其内存分配和回收都是由JRE在后台自动进行的。JRE提供一个后台线程进行检测和控制,一般在CPU空闲或内存不足时自动进行垃圾回收,自动释放不再被程序引用的对象,按照特定的垃圾回收算法。但程序员无法精确控制垃圾回收的时间和顺序等。
优点:提高编程效率;保护程序完整性。
缺点:开销影响性能。虚拟机必须跟踪程序中有用的对象,才能确定哪些是无用的对象。
特点:
1、垃圾回收只能回收内存资源,对其他物理资源,比如数据库连接,磁盘I/O等无能为力。
2、为了更快让垃圾回收,可以对无用对象引用变量设为null,暗示虚拟机可回收。
3、垃圾回收不可预知。可能定时/空闲/极限都有可能。可以System.gc方法建议回收,但仍有不确定性。除非finalize方法。
更新:16-3-22
建议回收:System.gc()或Runtime.getRuntime.gc()
通知系统进行垃圾回收,但系统是否进行垃圾回收依然不确定,但大部分时候,总会有一些效果,不会说程序的建议完全置之不理。
当系统要进行垃圾回收时,会调用默认的finalize()方法。但何时被调用时不确定的,不一定会执行。另外,任何类都可以重写finalize()方法,所以如果里面包含试图将可恢复对象重新变成可达状态的功能时会出现对象重新变成可达状态。
如果需要强制执行finalize()方法,在执行gc方法后,加上System.runFinalization()或Runtime.getRuntime.runFinalization()即可。
另外一些概念:
强引用:最常见,处于可达状态(包括常量池),不可能被回收。
软引用:SoftReference可能被回收。当系统内存足够时,不会被回收,只有当不足时才可能回收它。
弱引用:WeakReference不论内存是否足够,只要等到垃圾回收机制运行,总会被回收。
虚引用:类似于没有引用,不能单独使用,主要用于跟踪对象被垃圾回收的状态。
java
垃圾回收
点赞文章给优秀博主打call~
kef音响
精选推荐
Java语言通过其垃圾回收机制(GarbageCollection,GC)极大地简化了程序的内存管理。在Java中,程序员无需手动释放不再使用的对象所占用的内存,这一任务由垃圾回收器自动完成。程序员只需通过new关键字为对象申请内存空间,当对象不再被引用时,垃圾回收器会判断其为可回收对象,并在适当的时候进行回收,释放其占用的内存资源。
垃圾回收机制的存在,减轻了程序员管理内存的负担,使得程序员可以更加专注于程序的业务逻辑实现,而无需担心内存泄漏等问题。然而,这也增加了JVM(Java虚拟机)的负担,因为垃圾回收器需要监控每一个对象的运行状态,包括对象的申请、引用、被引用、赋值等,以确保准确、及时地释放对象。
什么是自动垃圾回收?
自动垃圾回收是一种在堆内存中找出哪些对象在被使用,还有哪些对象没被使用,并且将后者删掉的机制。
所谓使用中的对象(已引用对象),指的是程序中有指针指向的对象;而未使用中的对象(未引用对象),则没有被任何指针给指向,因此占用的内存也可以被回收掉。
在用C之类的编程语言时,程序员需要自己手动分配和释放内存。而Java不一样,它有垃圾回收器,释放内存由回收器负责。本文接下来将介绍垃圾回收机制的基本过程。
第一步:标记
垃圾回收的第一步是标记。垃圾回收器此时会找出哪些内存在使用中,还有哪些不是。
上图中,蓝色表示已引用对象,橙色表示未引用对象。垃圾回收器要检查完所有的对象,才能知道哪些有被引用,哪些没。如果系统里所有的对象都要检查,那这一步可能会相当耗时间。关注Java技术栈微信公众号,回复:JVM46,可以获取一份超全JVM调优攻略。
第二步:清除
这一步会删掉标记出的未引用对象。
内存分配器会保留指向可用内存的引用,以供分配新对象。
压缩
为了提升性能,删除了未引用对象后,还可以将剩下的已引用对象放在一起(压缩),这样就能更简单快捷地分配新对象了。
为什么需要分代垃圾收集?
之前说过,逐一标记和压缩Java虚拟机里的所有对象非常低效:分配的对象越多,垃圾回收需时就越久。不过,根据统计,大部分的对象,其实用没多久就不用了。JVM与Linux的内存关系详解,这篇推荐阅读。
来看个例子吧。(下图中,竖轴代表已分配的字节,而横轴代表程序运行时间)
上图可见,存活(没被释放)的对象随运行时间越来越少。而图中左侧的那些峰值,也表明了大部分对象其实都挺短命的。
JVM分代
根据之前的规律,就可以用来提升JVM的效率了。方法是,把堆分成几个部分(就是所谓的分代),分别是新生代、老年代,以及永生代。JVM运行时区域详解,这篇推荐大家看下。
新对象会被分配在新生代内存。一旦新生代内存满了,就会开始对死掉的对象,进行所谓的小型垃圾回收过程。一片新生代内存里,死掉的越多,回收过程就越快;至于那些还活着的对象,此时就会老化,并最终老到进入老年代内存。
StoptheWorld事件——小型垃圾回收属于一种叫"StoptheWorld"的事件。在这种事件发生时,所有的程序线程都要暂停,直到事件完成(比如这里就是完成了所有回收工作)为止。
老年代用来保存长时间存活的对象。通常,设置一个阈值,当达到该年龄时,年轻代对象会被移动到老年代。最终老年代也会被回收。这个事件成为MajorGC。
MajorGC也会触发STW(StoptheWorld)。通常,MajorGC会慢很多,因为它涉及到所有存活对象。所以,对于响应性的应用程序,应该尽量避免MajorGC。还要注意,MajorGC的STW的时长受年老代垃圾回收器类型的影响。
永久代包含JVM用于描述应用程序中类和方法的元数据。永久代是由JVM在运行时根据应用程序使用的类来填充的。此外,JavaSE类库和方法也存储在这里。
如果JVM发现某些类不再需要,并且其他类可能需要空间,则这些类可能会被回收。
世代垃圾收集过程
现在你已经理解了为什么堆被分成不同的代,现在是时候看看这些空间是如何相互作用的。后面的图片将介绍JVM中的对象分配和老化过程。关注Java技术栈微信公众号,回复:JVM46,可以获取一份超全JVM调优攻略。
首先,将任何新对象分配给eden空间。两个survivor空间都是空的。
当eden空间填满时,会触发轻微的垃圾收集。
引用的对象被移动到第一个survivor空间。清除eden空间时,将删除未引用的对象。
在下一次MinorGC中,Eden区也会做同样的操作。删除未被引用的对象,并将被引用的对象移动到Survivor区。然而,这里,他们被移动到了第二个Survivor区(S1)。
此外,第一个Survivor区(S0)中,在上一次MinorGC幸存的对象,会增加年龄,并被移动到S1中。待所有幸存对象都被移动到S1后,S0和Eden区都会被清空。注意,Survivor区中有了不同年龄的对象。
在下一次MinorGC中,会重复同样的操作。不过,这一次Survivor区会交换。被引用的对象移动到S0,。幸存的对象增加年龄。Eden区和S1被清空。
此幻灯片演示了promotion。在较小的GC之后,当老化的物体达到一定的年龄阈值(在该示例中为8)时,它们从年轻一代晋升到老一代。
随着较小的GC持续发生,物体将继续被推广到老一代空间。
所以这几乎涵盖了年轻一代的整个过程。最终,将主要对老一代进行GC,清理并最终压缩该空间。
电话+V:192606-48052
机构由一批拥有10年以上开发管理经验,且来自互联网或研究机构的IT精英组成,负责研究、开发教学模式和课程内容。公司具有完善的课程研发体系,一直走在整个行业发展的前端,在行业内竖立起了良好的品质口碑。