一 . 运行时数据区

程序计数器是线程私有的,是一块很小的内存空间,是当前线程执行到字节码行号的计数指示器。每个CPU处理器核心 在任何一个时刻,都只可能运行着唯一的一个线程,执行着一条指令。所以在多线程的应用中,线程不断切换和分配时间片。在线程切换来切换去的过程中,就是靠程序计数器来了解,该如果继续恢复运行该线程。

    虚拟机栈和Native方法栈也是线程私有的。在Sun HotSpot虚拟机中虚拟机栈和Native方法栈是被合二为一的。虚拟机栈描述的是Java方法执行的内存模型,栈帧用于存储局部变量表,方法出口等信息。每一个方法调用到执行完成都对应着一个栈帧在虚拟机栈中的入栈和出栈的过程。局部变量表中存放了八种基本数据类型和对象引用,还有returnAddress类型。前两种不难理解,returnAddress实际上是指向一条字节码指令的地址,局部变量表所需的内存空间在编译期间完成分配,当进入某个方法时,需要在栈帧中分配多大的局部空间是完全确定的,方法运行期间是不会改变局部变量表的大小。本地方法栈和虚拟机栈作用相似,虚拟机栈执行我们的java方法,本地方法栈就是执行Native方法,所以就是Native方法栈。简单地讲,一个Native Method就是一个java调用非java代码的接口。

Java堆是所有线程共享的区域,虚拟机管理的内存中最大的一块。基础所有对象的实例都是在这里分配内存。Java堆是GC的主要回收对象,虚拟机栈上局部变狼表所存的对象引用,就是指向堆内存中的一块地址。详细内容后面垃圾回收会提到更多。

    方法区也是一块所有线程共享的区域,这里存储虚拟机加载的类信息,常量,静态变量,JIT编译后的代码等数据。运行时常量池是方法区的一部分。

接下来要说到JVM GC机制,在垃圾回收中堆内存上移动对象位置是很常见的, 所以对象的访问方式也要顺便提一下,也可以展示下方法区的类型是如何被引用的。我们都知道栈上的局部变量表中,有存储reference数据的引用,它可能是对象的直接地址,也可能是句柄地址。

由于对象访问极其频繁,所以Hot Spot也使用第二种方式,直接存实例引用是效率比较高的。但是第一种句柄的方式,好处在于,垃圾回收中,不需要更改栈上所存储的地址,栈上的存储稳定,只需要修改句柄池。

二.垃圾回收GC

说到垃圾回收 ,就不得不说垃圾回收算法的思想, 说到回收算法, 又不得不想到,什么样的对象需要被回收?什么是存活对象,什么对象已死亡。判断对象的存活与死亡,通常有两种方法,引用计数法和可达性分析算法。引用计数算法的问题在于,无法解决两个对象间相互引用的问题,导致不得达的对象依然无法回收。下面是实例: 

A.b=B ;    //这里 B 引用计数+1   A对象在堆上   其属性b存着B的引用
B.a=A ; // 与上方同理
A=null;
B=null; //A B两对象栈上引用 给null AB堆上实例做到不可达
//此时导致 AB对象实例内存不会被回收

所以为了解决这个问题,Java虚拟机中 使用可达性分析算法。其思想是从可作为GC Root根结点的对象,向下搜索,搜索过的路成为引用链,凡事不能达到的对象,认为是可回收对象。有几种对象可以作为GC Root对象。

1. 虚拟机栈上(栈帧的本地变量表)引用的对象。   2. 方法区中类静态属性引用的对象。    3. 方法区中常量引用的对象      4.  本地方法栈上Native方法引用的对象。

试想一下,为什么这些对象可以作为GC Root,为什么其他对象无法作为GC Root。  比如你的一个接口,处理请求的时候,有很多线程本地变量 , 但是 处理完请求后,这些对象就都没用了,所以他们一般不能作为GC Root。什么时候本地变量会成为GC Root呢?  个人的猜测应该是在GC大面积回收,程序暂停的时候, 这个时候,不能把当前正在运行的数据和变量清理掉呀。这时候提升为GC Root是很恰当的我觉得。至于静态属性,常量什么的作为GC Root毋庸置疑了,他们本来生命周期就是整个应用程序生命周期。

    如何判断对象存活与死亡说过了,还需要了解的就是垃圾回收算法 。有四种思想需要提到, 其中有一种最基本的叫做 标记-清除算法。另外很重要的复制算法,是年轻代最合适的。还有一种标记整理算法,是老年代最合适的。最后一种就是分代这个思想。

    标记清除就是首先对所有需要回收的对象进行标记,最后统一进行清除。这样的做法效率不高,清理后内存碎片很多,可能导致后期大对象无法分配内存,会经常触发另一次垃圾回收。

    复制算法的思想是,将内存分为两块,其中一块保持为空,回收的时候,将存活的对象复制到空的一块,复制完成后,对原来那半内存全部清理。但是java虚拟机并不能留出一半的内存,这样太浪费资源,并且在Java堆中,年轻代里绝大部分内存都是要被回收的。所以Hot Spot中,将年轻代分为8:1:1的Eden,Survivor  * 2, 就是一块Eden , 两块Survivor。  所以年轻代的策略,优先使用大的Eden,必须保持一块Survivor为空。回收的时候,将存活的对象,复制到空的Survivor内存区域,清理Eden和刚才使用的Survivor。

如果Survivor放不下存活的对象了,和时候 就该有对象进入老年代了~     老年代使用标记—整理算法。标记整理思路就是,先标记,然后在回收的时候,将存活的对象移动到一端,将被清理的移动到另一端。然后清理端边界意外的内存。

  

  

Java JVM运行时数据区,内存管理和GC垃圾回收的更多相关文章

  1. Java内存管理:Java内存区域 JVM运行时数据区

    转自:https://blog.csdn.net/tjiyu/article/details/53915869 下面我们详细了解Java内存区域:先说明JVM规范定义的JVM运行时分配的数据区有哪些, ...

  2. Java中的字符串常量池和JVM运行时数据区的相关概念

    什么是字符串常量池 JVM为了减少字符串对象的重复创建,其维护了一个特殊的内存,这段内存被成为字符串常量池或者字符串字面量池 工作原理 当代码中出现字面量形式创建字符串对象时,JVM首先会对这个字面量 ...

  3. JVM运行时数据区及对象在内存中初始化的过程

    JVM运行时数据区 Java虚拟机所管理的内存区域,也称为运行时数据区,分为以下几个运行时数据区,如图所示 程序计数器:当前程序所执行字节码的行号指示器 程序计数器(Program Counter R ...

  4. JVM运行时数据区与JVM堆内存模型小结

    前提 JVM运行时数据区和JVM内存模型是两回事,JVM内存模型指的是JVM堆内存模型. 那JVM运行时数据区又是什么? 它包括:程序计数器.虚拟机栈.本地方法栈.方法区.堆. 来看看它们都是干嘛的 ...

  5. Jvm运行时数据区 —— Java虚拟机结构小记

    关于jvm虚拟机的文章网上都讲烂了.尤其是jvm运行时数据区的内容. 抱着眼见为实的想法,自己翻了翻JVM规范,花了点时间稍微梳理了一下. 以下是阅读Java虚拟机规范(Java SE 8版)的第二章 ...

  6. JVM运行时数据区(二)

    4.本地方法栈 本地方法栈与虚拟机栈所发挥的作用是非常相似的,它们之间的区别不过是虚拟机栈为虚拟机执行Java方法服务,而本地方法栈则为虚拟机使用到的Native方法服务. 与Java虚拟机栈一样本地 ...

  7. Jvm运行时数据区

    一:运行时数据区 Java虚拟机在执行Java程序的过程中会把它管理的内存分为若干个不同的数据区域.这些区域有着各自的用途,一级创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有些区域则依赖用户 ...

  8. JVM 运行时数据区 (三)

    JVM运行时数据区 运行时数据区由 程序计数器.java虚拟机栈.本地方法栈.堆.方法区 组成: 1.程序计数器 每一个Java线程都有一个程序计数器,用于保存程序执行到当前方法的哪一个指令,它是线程 ...

  9. JVM总结(一):概述--JVM运行时数据区

    大三下,趁着寒假重温一遍JVM,准备在一个系列来总价一下学习JVM的整个过程.争取在接下来的一个星期内更新完这一个系列,然后回家过年. JVM运行时数据区 线程私有的数据区 程序计数器 虚拟机栈 本地 ...

随机推荐

  1. decode和encode

    作者:于洋链接:https://www.zhihu.com/question/23374078/answer/69732605来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出 ...

  2. chmod 权限 命令详细用法

    指令名称 : chmod 使用权限 : 所有使用者 使用方式 : chmod [-cfvR] [--help] [--version] mode file... 说明 : Linux/Unix 的档案 ...

  3. IIS7 MVC 403 禁止访问:访问被拒绝

  4. iOS手机号,身份证,车牌号正则表达式

    1.手机号判断,根据维基百科2016年6月修订的段号判断 是否是手机号 /** 手机号码 13[0-9],14[5|7|9],15[0-3],15[5-9],17[0|1|3|5|6|8],18[0- ...

  5. Python进阶(三十五)-Fiddler命令行和HTTP断点调试

    Python进阶(三十五)-Fiddler命令行和HTTP断点调试 一. Fiddler内置命令   上一节(使用Fiddler进行抓包分析)中,介绍到,在web session(与我们通常所说的se ...

  6. Writing your first Django

    Quick install guide 1.1   Install Python, it works with Python2.6, 2.7, 3.2, 3.3. All these version ...

  7. MAC版Eclipse的常用快捷键

    一.Command类 Command+1 快速修复 Command+d 删除当前行 Command+Option+↓ 复制当前行到下一行 Command+Option+↑ 复制当前行到上一行 Comm ...

  8. JAVA字符串怎么转换成整数

    首先你要确定你的字符串可以转换为int类型的,比如说: String s = "123"; 如果String s = "abc";则转换时会报错! 需要的包是& ...

  9. gSoap的“error LNK2001: 无法解析的外部符号 _namespaces”解决方法

    错误 2 error LNK2001: 无法解析的外部符号 _namespaces 解决方法: 1. 在工程中定义 WITH_NONAMESPACES 宏 2.尝试 "#include &q ...

  10. java IO【转】

    Java 流在处理上分为字符流和字节流.字符流处理的单元为 2 个字节的 Unicode 字符,分别操作字符.字符数组或字符串,而字节流处理单元为 1 个字节,操作字节和字节数组. Java 内用 U ...