java中的垃圾回收机制

2020-11-04 09:17发布

7条回答
那些年很冒险的梦。
2楼 · 2020-11-04 09:20

一:垃圾回收机制的意义

java  语言中一个显著的特点就是引入了java回收机制,是c++程序员最头疼的内存管理的问题迎刃而解,它使得java程序员在编写程序的时候不在考虑内存管理。由于有个垃圾回收机制,java中的额对象不在有“作用域”的概念,只有对象的引用才有“作用域”。垃圾回收可以有效的防止内存泄露,有效的使用空闲的内存;

说到这,不得不提起内存泄漏(memory leak)和内存溢出(out of memory

内存泄漏是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄漏似乎不会有大的影响,但内存泄漏堆积后的后果就是内存溢出。

内存溢出:指程序申请内存时,没有足够的内存供申请者使用,或者说,给了你一块存储int类型数据的存储空间,但是你却存储long类型的数据,那么结果就是内存不够用,此时就会报错OOM,即所谓的内存溢出。 

通俗的说就是停车场(堆)保安(gc)让很久不用的废弃车子(无用的对象)从车位上挪走,但是这个车子又没办法挪走。这就是内存泄漏。停车场所有的车位都有车子占用了,再来车子没地了,或者说给你一个小汽车的停车位(int),你非要停一辆高铁(Long),这就是内存溢出。

内存泄露量大到一定程度会导致内存溢出。但是内存溢出不一定是内存泄露引起的。


我是大脸猫
3楼 · 2020-11-04 09:24

将图南


Java的垃圾回收机制

垃圾收集GC(Garbage Collection)是Java语言的核心技术之一, 在Java中,程序员不需要去关心内存动态分配和垃圾回收的问题,这一切都交给了JVM来处理。针对GC我们这篇文章提出以下几个问题,GC中判定为垃圾的标准,标记垃圾的算法以及回收垃圾的算法。

什么样的对象才是垃圾?

这个问题其实很简单,对于Java对象来讲,如果说这个对象没有被其他对象所引用该对象就是无用的,此对象就被称为垃圾,其占用的内存也就要被销毁。那么自然而然的就引出了我们的第二个问题,判断对象为垃圾的算法都有哪些?

标记垃圾的算法

Java中标记垃圾的算法主要有两种, 引用计数法和可达性分析算法。我们首先来介绍引用计数法。

引用计数法

引用计数法就是给对象中添加一个引用计数器,每当有一个地方引用它,计数器就加 1;当引用失效,计数器就减 1;任何时候计数器为 0 的对象就是不可能再被使用的,可以当做垃圾收集。这种方法实现起来很简单而且优缺点都很明显。

  • 优点 执行效率高,程序执行受影响较小

  • 缺点 无法检测出循环引用的情况,导致内存泄露

优点我们很好理解,那么什么是循环引用呢?我们举一个简单的例子。

 
public class MyObject {
    public MyObject childNode;
}

 

复制代码

public class ReferenceCounterProblem {
    public static void main(String[] args) {
        MyObject object1 = new MyObject();
        MyObject object2 = new MyObject();
        object1.childNode = object2;
        object2.childNode = object1;
    }
}

复制代码

 

从上述代码中我们可以看出,object1和object2并没有任何价值,但是他们循环引用,造成内存泄露。

可达性分析算法

这个算法的基本思想就是通过一系列的称为 “GC Roots” 的对象作为起点,从这些节点开始向下搜索,节点所走过的路径称为引用链,当一个对象到 GC Roots 没有任何引用链相连的话,则证明此对象是不可用的。

那么什么对象可以作为GCRoot?

  • 虚拟机栈中的引用对象

  • 方法区中的常量引用对象

  • 方法区中的类静态属性引用对象

  • 本地方法栈中的引用对象

  • 活跃线程中的引用对象

可达性分析算法如下图所示

0c7506f0dd23f0e6f7d5f9c98c29d95e.jpeg

那么不可达的对象是否是必死之局呢?答案也是否定的

在可达性分析法中不可达的对象,它们暂时处于“缓刑阶段”,要真正宣告一个对象死亡,至少要经历两次标记过程;可达性分析法中不可达的对象被第一次标记并且进行一次筛选,筛选的条件是此对象是否有必要执行 finalize 方法。当对象没有覆盖 finalize 方法,或 finalize 方法已经被虚拟机调用过时,虚拟机将这两种情况视为没有必要执行。被判定为需要执行的对象将会被放在一个队列中进行第二次标记,除非这个对象与引用链上的任何一个对象建立关联,否则就会被真的回收。

如何将垃圾回收?

在Java中存在着四种垃圾回收算法,标记清除算法、复制算法、标记整理算法以及分代回收算法。我们接下来会分别介绍他们。

标记清除算法

该算法分为“标记”和“清除”两个阶段:标记阶段的任务是标记出所有需要被回收的对象,清除阶段就是回收被标记的对象所占用的空间。它是最基础的收集算法,效率也很高,但是会带来两个明显的问题:

  • 效率问题

  • 空间问题(标记清除后会产生大量不连续的碎片)

该算法具体流程如下图所示

57b736ac2feb667814051089be175047.jpeg

复制算法

为了解决效率问题,我们开发出了复制算法。它可以将内存分为大小相同的两块,每次使用其中的一块。当第一块的内存使用完后,就将还存活的对象复制到另一块去,然后再把使用的空间一次清理掉。这样就使每次的内存回收都是对内存区间的一半进行回收。

简单来说就是该对象分为对象面以及空闲面,对象在对象面上创建,对象面上存活的对象会被复制到空闲面,接下来就可以清除对象面的内存。

这种算法的优缺点也比较明显

  • 优点:解决碎片化问题,顺序分配内存简单高效

  • 缺点:只适用于存活率低的场景,如果极端情况下如果对象面上的对象全部存活,就要浪费一半的存储空间。

标记整理算法

为了解决复制算法的缺陷,充分利用内存空间,提出了标记整理算法。该算法标记阶段和标记清除一样,但是在完成标记之后,它不是直接清理可回收对象,而是将存活对象都向一端移动,然后清理掉端边界以外的内存。 如下图所示:

a680d77ff6a27e87a73f5a1b891eecae.jpeg

分代收集算法

当前虚拟机的垃圾收集都采用分代收集算法,这种算法就是根据具体的情况选择具体的垃圾回收算法。一般将 java 堆分为新生代和老年代,这样我们就可以根据各个年代的特点选择合适的垃圾收集算法。

比如在新生代中,每次收集都会有大量对象死去,所以可以选择复制算法,只需要付出少量对象的复制成本就可以完成每次垃圾收集。而老年代的对象存活几率是比较高的,而且没有额外的空间对它进行分配担保,所以我们必须选择“标记-清除”或“标记-整理”算法进行垃圾收集。


哆啦公
4楼 · 2020-11-04 09:50

java 的垃圾回收机制: 1.垃圾回收是由虚拟机自动执行,不能人为地干预。

2.系统比较空闲(垃圾回收线程) 3.对象不在被引用.对象处于引用的隔离岛状态(隔离引用),对象具备了回收的条件 4.gc()方法,可以建议虚拟机执行垃圾回收,但是不能确定是否会执行回收。


魏魏姐
5楼 · 2020-11-04 10:20

java 的垃圾回收机制: 1.垃圾回收是由虚拟机自动执行,不能人为地干预。

2.系统比较空闲(垃圾回收线程) 3.对象不在被引用.对象处于引用的隔离岛状态(隔离引用),对象具备了回收的条件 4.gc()方法,可以建议虚拟机执行垃圾回收,但是不能确定是否会执行回收。


visonx
6楼 · 2020-11-04 10:20

java 的垃圾回收机制: 

1.垃圾回收是由虚拟机自动执行,不能人为地干预。

2.系统比较空闲(垃圾回收线程) 3.对象不在被引用.对象处于引用的隔离岛状态(隔离引用),对象具备了回收的条件 4.gc()方法,可以建议虚拟机执行垃圾回收,但是不能确定是否会执行回收。


樱田妮妮NiNi
7楼 · 2020-11-04 18:34

在一般的Java程序中,见到最多的就是强引用(strong reference)。如Date date = new Date(),date就是一个对象的强引用。对象的强引用可以在程序中到处传递。很多情况下,会同时有多个引用指向同一个对象。强引用的存在限制了对象在内存中的存活时间。假如对象A中包含了一个对象B的强引用,那么一般情况下,对象B的存活时间就不会短于对象A。如果对象A没有显式的把对象B的引用设为null的话,就只有当对象A被垃圾回收之后,对象B才不再有引用指向它,才可能获得被垃圾回收的机会。

除了强引用之外,java.lang.ref包中提供了对一个对象的不同的引用方式。JVM的垃圾回收器对于不同类型的引用有不同的处理方式。

软引用

软引用(soft reference)在强度上弱于强引用,通过类SoftReference来表示。它的作用是告诉垃圾回收器,程序中的哪些对象是不那么重要,当内存不足的时候是可以被暂时回收的。当JVM中的内存不足的时候,垃圾回收器会释放那些只被软引用所指向的对象。如果全部释放完这些对象之后,内存还不足,才会抛出OutOfMemory错误。软引用非常适合于创建缓存。当系统内存不足的时候,缓存中的内容是可以被释放的。比如考虑一个图像编辑器的程序。该程序会把图像文件的全部内容都读取到内存中,以方便进行处理。而用户也可以同时打开多个文件。当同时打开的文件过多的时候,就可能造成内存不足。如果使用软引用来指向图像文件内容的话,垃圾回收器就可以在必要的时候回收掉这些内存。


不吃鱼的猫
8楼 · 2020-11-05 09:24

垃圾收集GC(Garbage Collection)是Java语言的核心技术之一, 在Java中,程序员不需要去关心内存动态分配和垃圾回收的问题,这一切都交给了JVM来处理。

相关问题推荐

  • 回答 2

    Statement的execute(String query)方法用来执行任意的SQL查询,如果查询的结果是一个ResultSet,这个方法就返回true。如果结果不是ResultSet,比如insert或者update查询,它就会返回false。我们可以通过它的getResultSet方法来获取ResultSet,或者通过getUpda...

  • 回答 22

    忙的时候项目期肯定要加班 但是每天加班应该还不至于

  • 回答 108
    已采纳

    虽然Java人才越来越多,但是人才缺口也是很大的,我国对JAVA工程师的需求是所有软件工程师当中需求大的,达到全部需求量的60%-70%,所以Java市场在短时间内不可能饱和。其次,Java市场不断变化,人才需求也会不断增加。马云说过,未来的制造业要的不是石油,...

  • 回答 5
    已采纳

    工信部证书含金量较高。工信部是国务院的下属结构,具有发放资质、证书的资格。其所发放的证书具有较强的权威性,在全国范围内收到认可,含金量通常都比较高。 工信部证书,其含义也就是工信部颁发并承认的某项技能证书,是具有法律效力的,并且是国家认可的...

  • 回答 70
    已采纳

    学Java好不好找工作?看学完Java后能做些什么吧。一、大数据技术Hadoop以及其他大数据处理技术都是用Java或者其他,例如Apache的基于Java 的 HBase和Accumulo以及ElasticSearchas。但是Java在此领域并未占太大空间,但只要Hadoop和ElasticSearchas能够成长壮...

  • 回答 16
    已采纳

    就是java的基础知识啊,比如Java 集合框架;Java 多线程;线程的五种状态;Java 虚拟机;MySQL (InnoDB);Spring 相关;计算机网络;MQ 消息队列诸如此类

  • 回答 12

    #{}和${}这两个语法是为了动态传递参数而存在的,是Mybatis实现动态SQL的基础,总体上他们的作用是一致的(为了动态传参),但是在编译过程、是否自动加单引号、安全性、使用场景等方面有很多不同,下面详细比较两者间的区别:1.#{} 是 占位符 :动态解析 ...

  • 回答 62

    没问题的,专科学历也能学习Java开发的,主要看自己感不感兴趣,只要认真学,市面上的培训机构不少都是零基础课程,能跟得上,或是自己先找些资料学习一下。

  • 回答 4

    1、反射对单例模式的破坏采用反射的方式另辟蹊径实例了该类,导致程序中会存在不止一个实例。解决方案其思想就是采用一个全局变量,来标记是否已经实例化过了,如果已经实例化过了,第 二次实例化的时候,抛出异常2、clone()对单例模式的破坏当需要实现单例的...

  • 回答 5

     优点: 一、实例控制  单例模式会阻止其他对象实例化其自己的单例对象的副本,从而确保所有对象都访问唯一实例。 二、灵活性  因为类控制了实例化过程,所以类可以灵活更改实例化过程。 缺点: 一、开销  虽然数量很少,但如果每次对象请求引用时都要...

  • 回答 4

    这个主要是看你数组的长度是多少, 比如之前写过的一个程序有个数组存的是各个客户端的ip地址:string clientIp[4]={XXX, xxx, xxx, xxx};这个时候如果想把hash值对应到上面四个地址的话,就应该对4取余,这个时候p就应该为4...

  • 回答 6

     哈希表的大小 · 关键字的分布情况 · 记录的查找频率 1.直接寻址法:取关键字或关键字的某个线性函数值为散列地址。即H(key)=key或H(key) = a·key + b,其中a和b为常数(这种散列函数叫做自身函数)。...

  • 回答 6

    哈希表的大小取决于一组质数,原因是在hash函数中,你要用这些质数来做模运算(%)。而分析发现,如果不是用质数来做模运算的话,很多生活中的数据分布,会集中在某些点上。所以这里最后采用了质数做模的除数。 因为用质数做了模的除数,自然存储空间的大小也用质数了...

  • 回答 2

    是啊,哈希函数的设计至关重要,好的哈希函数会尽可能地保证计算简单和散列地址分布均匀,但是,我们需要清楚的是,数组是一块连续的固定长度的内存空间

  • 回答 3

     解码查表优化算法,seo优化

  • 回答 5

    1.对对象元素中的关键字(对象中的特有数据),进行哈希算法的运算,并得出一个具体的算法值,这个值 称为哈希值。2.哈希值就是这个元素的位置。3.如果哈希值出现冲突,再次判断这个关键字对应的对象是否相同。如果对象相同,就不存储,因为元素重复。如果对象不同,就...

没有解决我的问题,去提问