zoukankan      html  css  js  c++  java
  • 大数据基础篇----jvm的知识点归纳-5个区和垃圾回收机制

    一直对jvm看了又忘,忘了又看的。今天做一个笔记整理存放在这里。

    我们先看一下JVM的内存模型图:

    上面有5个区,这5个区干嘛用的呢?

    我们想象一个场景:

    我们有一个class文件,里面有很多的类的定义是不是,类的定义放在什么地方呢?类的定义就放在方法区里面。

    程序在运行时会产生很多的对象,比如LinkList等这些对象就存放在堆里面。

    栈:

    我们的程序在运行时本质上就是启动线程在运行,比如main函数就是一个主线程。一个main主线程可以有很多的子线程。

    线程在工作就是执行我们的各种方法。方法里面肯定有我们自己定义了一些局部的变量,比如我们在方法里面new了一个对象,对象肯定是放在堆里面的,但是对堆的引用我们就放在栈里面。那么栈就有问题了,我们一个程序有很多的线程,如果把所有的线程里面的变量存放在一起,肯定有会有变量是重复的,冲突。所有不能放在一起。所以栈里面是分线程来存放的每一个线程都是自己的栈空间,线程私有的。堆是线程共享的。     

    栈里面有一个细节:

    就是说一个栈空间是以不同的线程区分开来。每个线程有自己栈,每个线程里面又会执行很多的方法,每一个方法对应一个栈帧:

    每个方法执行时都会创建一个栈帧(Stack Frame)用语存储局部变量表、操作数栈、动态链接、方法出口等信息。从下图从可以看到,每个线程在执行一个方法时,都意味着有一个栈帧在当前线程对应的栈帧中入栈和出栈。

    图中可以看到每一个栈帧中都有局部变量表。局部变量表存放了编译期间的各种基本数据类型,对象引用等信息。

    好了,我们看一下具体的东西:

    本地方法栈(Native Stack

             本地方法栈(Native Stack)与Java虚拟机站(Java Stack)所发挥的作用非常相似,他们之间的区别在于虚拟机栈为虚拟机栈执行java方法(也就是字节码)服务,而本地方法栈则为使用到Native方法服务。

     堆(Heap

             对于大多数应用来说,Java Heap是Java虚拟机管理的内存的最大一块,这块区域随着虚拟机的启动而创建。在实际的运用中,我们创建的对象和数组就是存放在堆里面。如果你听说线程安全的问题,就会很明确的知道Java Heap是一块共享的区域,操作共享区域的成员就有了锁和同步。在程序的运行中不断地new 对象,就存在堆里面。

             与Java Heap相关的还有Java的垃圾回收机制(GC),Java Heap是垃圾回收器管理的主要区域。程序猿所熟悉的新生代、老生代、永久代的概念就是在堆里面,现在大多数的GC基本都采用了分代收集算法。如果再细致一点,Java Heap还有Eden空间,From Survivor空间,To Survivor空间等。

             Java Heap可以处于物理上不连续的内存空间中,只要逻辑上是连续的即可。

     

    上面这张图就是我们新生代,老年代的图。涉及到垃圾回收机制。

    我们来介绍一下垃圾回收机制:

    刚开始时创建的对象都存放在Eden Sapce里面(伊甸园,新生代),大家都无忧无虑的。然后呢 ,垃圾回收机制来了。先对生活在伊甸园的对象检测一次,发现还有利用价值就把对象放在Survivor空间里面的From Space,survivior空间分为两块,一块是From Space,一块是ToSapce空间。ToSpace空间是很少用的(就是用来做垃圾回收的挪动的)。然后垃圾回收机制对From Space的对象回收比如18次,还能幸存下来,就放在老年代里面(Old Generation)。我们很奇怪,这里的ToSpace是干嘛用的。

    好了我们来介绍下垃圾回收算法:

    有 两种算法。

    1:对象A有没有引用对象B.有引用就不是垃圾,这种方法有问题。A,B相互引用,就不能区分出是不是垃圾了。

    2:根节点搜索。从根节点往下搜索。能搜索到了就不是垃圾,不能搜索到的,就是垃圾。

     这是由映射表记录的,再详细就不知道了。

    对象其实就是一个方格:

    如上,红色是好的对象,黑色的是垃圾对象。

    我们怎么去回收黑色的对象呢:

    方法一:标志-清除:

    直接把黑色的对象清除掉。

    但是有一个问题:这样清除掉的恶化,我的空间变得很零散。下次要放一个大的对象的话(必须是一个连续的空间)比如四个格子,就放不下去了。

    方法二:标记整理:

     我只移动有用的:把红色的有用的对象移动到白色的空白地方。但是造成的问题是:对在运行的程序有影响。

    方法三:

    复制算法:

    预先存留一块有用的的空间:那就是上文提到的ToSpace空间。

     在FromSpace空间中,垃圾回收机制把没用的的对象标记成黑色的,然后把红色的有用的对象都转移到右边的ToSpace空间,到垃圾回收机制把左边的黑色和红色全部清除之后。再把右边的ToSpace的那些红色有用对象再移植到左边的FromSpace空间。这样就整齐了。

    然后我们会想一个问题。那右边给他预留这么大的空间不是很浪费吗?其实实际上右边的空间不需要那么大,只要一点点就够了。如下图

    因为我们的有用的对象(红色的方块)其实是很少的。很多对象用好一次就不用了的。

      方法区(Method Area

             方法区(Method Area)与堆(Java Heap)一样,是各个线程共享的内存区域,它用于存储虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据。虽然Java虚拟机规范把方法区描述为堆的一个逻辑部分,但是她却有一个别名叫做非堆(Non-Heap)。分析下Java虚拟机规范,之所以把方法区描述为堆的一个逻辑部分,应该觉得她们都是存储数据的角度出发的。一个存储对象数据(堆),一个存储静态信息(方法区)。

             在上文中,我们看到堆中有新生代、老生代、永久代的描述。为什么我们将新生代、老生代、永久代三个概念一起说,那是因为HotSpot虚拟机的设计团队选择把GC分代收集扩展至方法区,或者说使用永久代来实现方法区而已。这样HotSpot的垃圾收集器就能想管理Java堆一样管理这部分内存。简单点说就是HotSpot虚拟机中内存模型的分代,其中新生代和老生代在堆中,永久代使用方法区实现。根据官方发布的路线图信息,现在也有放弃永久代并逐步采用Native Memory来实现方法区的规划,在JDK1.7的HotSpot中,已经把原本放在永久代的字符串常量池移出。

  • 相关阅读:
    架构-LAMP特级学习(网站加速解决方案)
    架构-LAMP特级学习(网站大存储量解决方案)
    架构-LAMP特级学习(网站大访问量解决方案)
    Shell-学习笔记
    算法-随手写的冒泡排序
    算法-随手写的二分查找
    cocos2dx 3.x ccPositionTextureColor_vert与ccPositionTextureColor_noMVP_vert
    cocos2dx当节点存在缩放时要注意的问题
    cocos2dx 3.x draw debug
    cocos2dx 3.x ccDrawLine一个坑
  • 原文地址:https://www.cnblogs.com/shenxiaoquan/p/6262066.html
Copyright © 2011-2022 走看看