Java虚拟机所管理的内存将会包括以下几个运行时数据区域:

1,程序计数器Program Counter Register

一块较小的内存空间,非所有线程共享的区域,每个程序计数器,都会记录当前线程执行到的位置。

由于多线程之间会互相切换,为了在切换以后还能恢复到正确的执行位置,每条线程都有自己独立的程序计数器,他们之间互不影响,独立存储,称这块区域为“线程私有”的内存。

如果正在执行的是java方法,那么计数器记录的就是正在执行的虚拟机字节码指令的地址;如果正在执行的是Native方法,计数器就为空(Undefined).

虚拟机字节码,字节码解释器工作时,就是通过改变程序计数器的值来选取下一条需要执行的字节码指定,分支,循环,跳转,异常处理,线程恢复等基础功能都需要依赖这个计数器来完成。

蚂蚁课堂带你学Java

2,虚拟机栈 VM Stack

线程私有的,生命周期与线程相同

虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧(Stack Frame,方法运行时的基础数据结构),用于存储局部变量表,操作数栈,动态链接,方法出口等信息。

每个方法调用直至执行完成,都对应着一个栈帧在虚拟机栈中入栈到出栈的过程。

虚拟机栈中有一个局部变量表的部分,存放了编译期可知的八大基本数据类型,对象引用类型(reference),returnAddress类型(指向一条字节码指令的地址)

局部变量表所需的空间会在编译期分配完成。当进入一个方法时,这个方法需要在栈帧中分配多大的局部变量空间是完全确定的,在运行期间是不会改变局部变量表大小的。

3,本地方法栈 Native Method Stack

本地方法栈为虚拟机使用到的native方法服务,和虚拟机栈类似,只是一个是java方法,一个是本地方法。虚拟机规范中没有对本地方法使用的语言,方式,数据结构做出强制规定,可以由具体的虚拟机自由实现。甚至有的虚拟机把本地方法栈和虚拟机栈合二为一。

4,堆 Heap

虚拟机所管理的内存中最大的一块,被所有线程共享的一块区域,在虚拟机启动时创建。用来存放对象实例。虚拟机规范中说:所有的对象实例以及数组都要在堆上分配(随着技术的发展,可能有一些其他的优化方案,就不那么绝对了)

垃圾收集:

Java堆是垃圾收集器管理的主要区域,因此很多时候也被称做GC堆,Garbage Collected Heap.

因为收集器都采用分代算法,所有java堆可以细分为:新生代,老年代,,多个线程私有的分配缓冲区(Thread Local Allocation Buffer,TLAB)等,都是存放的对象实例。

划分目的是为了更好的回收/分配内存。

5,方法区 Method Area

所有线程共享区域,用于存储已经被虚拟机加载的常量,静态变量,类信息,即时编译器编译后的代码等数据。

虚拟机规范把方法区描述为堆中的一个逻辑部分,但是它的别名叫做Non-Heap(非堆),目的就是为了和Java堆区分开来。

虚拟机规范可以允许方法区不实现垃圾回收,内存在这个区域的回收主要是常理池的回收和对类型的卸载。所以这个部分的回收其实是必要的。

6,运行时常量迟

属于方法区一部分,用于存放编译期生成的各种字面量和符号引用。编译器和运行期(String 的 intern() )都可以将常量放入池中。内存有限,无法申请时抛出 OutOfMemoryError。

7,直接内存

非虚拟机运行时数据区的部分

在 JDK 1.4 中新加入 NIO (New Input/Output) 类,引入了一种基于通道(Channel)和缓存(Buffer)的 I/O 方式,它可以使用 Native 函数库直接分配堆外内存,然后通过一个存储在 Java 堆中的 DirectByteBuffer 对象作为这块内存的引用进行操作。可以避免在 Java 堆和 Native 堆中来回的数据耗时操作。

OutOfMemoryError:会受到本机内存限制,如果内存区域总和大于物理内存限制从而导致动态扩展时出现该异常。

蚂蚁课堂带你学Java

垃圾回收器与内存分配策略

概述

程序计数器、虚拟机栈、本地方法栈 3 个区域随线程生灭(因为是线程私有),栈中的栈帧随着方法的进入和退出而有条不紊地执行着出栈和入栈操作。

而 Java 堆和方法区则不一样,一个接口中的多个实现类需要的内存可能不一样,一个方法中的多个分支需要的内存也可能不一样,我们只有在程序处于运行期才知道那些对象会创建,这部分内存的分配和回收都是动态的,垃圾回收期所关注的就是这部分内存。

在进行内存回收之前要做的事情就是判断那些对象是‘死’的,哪些是‘活’的。

引用计数法

给对象添加一个引用计数器,但是难以解决循环引用问题。

可达性分析法

通过一系列的 ‘GC Roots’ 的对象作为起始点,从这些节点出发所走过的路径称为引用链。当一个对象到 GC Roots 没有任何引用链相连的时候说明对象不可用。

可作为 GC Roots 的对象:

  • 虚拟机栈(栈帧中的本地变量表)中引用的对象
  • 方法区中类静态属性引用的对象
  • 方法区中常量引用的对象
  • 本地方法栈中 JNI(即一般说的 Native 方法) 引用的对象

回收方法区

在堆中,尤其是在新生代中,一次垃圾回收一般可以回收 70% ~ 95% 的空间,而永久代的垃圾收集效率远低于此。

永久代垃圾回收主要两部分内容:废弃的常量和无用的类。

判断废弃常量:一般是判断没有该常量的引用。

判断无用的类:要以下三个条件都满足

  • 该类所有的实例都已经回收,也就是 Java 堆中不存在该类的任何实例
  • 加载该类的 ClassLoader 已经被回收
  • 该类对应的 java.lang.Class 对象没有任何地方呗引用,无法在任何地方通过反射访问该类的方法

Java 内存模型与线程

Java 内存模型

屏蔽掉各种硬件和操作系统的内存访问差异。

主内存和工作内存之间的交互

蚂蚁课堂带你学Java

  • 原子性(Atomicity)

由 Java 内存模型来直接保证的原子性变量操作包括 read、load、assign、use、store 和 write。大致可以认为基本数据类型的操作是原子性的。同时 lock 和 unlock 可以保证更大范围操作的原子性。而 synchronize 同步块操作的原子性是用更高层次的字节码指令 monitorenter 和 monitorexit 来隐式操作的。

  • 可见性(Visibility)

是指当一个线程修改了共享变量的值,其他线程也能够立即得知这个通知。主要操作细节就是修改值后将值同步至主内存(volatile 值使用前都会从主内存刷新),除了 volatile 还有 synchronize 和 final 可以保证可见性。同步块的可见性是由“对一个变量执行 unlock 操作之前,必须先把此变量同步会主内存中( store、write 操作)”这条规则获得。而 final 可见性是指:被 final 修饰的字段在构造器中一旦完成,并且构造器没有把 “this” 的引用传递出去( this 引用逃逸是一件很危险的事情,其他线程有可能通过这个引用访问到“初始化了一半”的对象),那在其他线程中就能看见 final 字段的值。

  • 有序性(Ordering)

如果在被线程内观察,所有操作都是有序的;如果在一个线程中观察另一个线程,所有操作都是无序的。前半句指“线程内表现为串行的语义”,后半句是指“指令重排”现象和“工作内存与主内存同步延迟”现象。Java 语言通过 volatile 和 synchronize 两个关键字来保证线程之间操作的有序性。volatile 自身就禁止指令重排,而 synchronize 则是由“一个变量在同一时刻指允许一条线程对其进行 lock 操作”这条规则获得,这条规则决定了持有同一个锁的两个同步块只能串行的进入。

更多了解请关注小编的下一篇文章(下)

小编为大家创建了一个Java程序员的交流平台894180257,欢迎大家前来加入。

蚂蚁课堂带你学Java

程序员交流平台_Java虚拟机所管理的内存到底有哪些?Java程序员必看栏目(上)...相关推荐

  1. 第一个java程序释义_Java 学习之路(1)第一个Java程序

    Hello World程序 在编程语言的世界里,第一个编程语言估计就是输出Hello World了吧. /** * 编写第一个Java程序,输出Hello World! * @author LJS * ...

  2. java程序员面试时候经常会问的一些问题_面试JAVA程序员常遇到的一些问题了解一下...

    每当我们去面试的时候,面试官总会问我们一大堆问题,而回答问题都是有技巧,回答问题的时候不能过于老实,全盘脱出,稍微夸大或者隐瞒是没什么问题,但不能过度.因为最重要的还是靠自身的实力,作为JAVA程序员 ...

  3. java多线程死锁代码_java多线程死锁 编写高质量代码:改善Java程序的151个建议...

    java多线程死锁 编写高质量代码:改善Java程序的151个建议 第1章 Java开发中的通用方法和准则 建议1:不要在常量和变量中出现易混淆的字母 建议2:莫让常量蜕变成变量 建议3:三元操作符的 ...

  4. java内存漏洞_处理Java程序中的内存漏洞

    Java 程序中也有内存漏洞?当然有.与流行的观念相反,在 Java 编程中,内存治理仍然是需要考虑的问题.在本文中,您将了解到什么会导致内存漏洞以及何时应该关注这些漏洞.您还有机会实践一下在您自己的 ...

  5. java 平均值_Java岗招聘标准差强人意,薪资比拼,Java程序员表示“我太难了”...

    在广大国民都认为程序员高收入的同时,这些阿猿们对自己的薪资还不是很满意.调查显示,超过半数程序员对自己的薪资不满意甚至是很不满意,40%的程序员认为薪资一般,仅极少数人对薪资较为满意,其中90%的程序 ...

  6. 程序员进阶!我的移动开发春季历程,2年以上经验必看

    前言 对于android开发,我们大部分工作都是在应用层,但为了体现"技术含量",以及"知其所以然",以便在遇到具体问题时不至于束手无策,因此有必要了解底层的工 ...

  7. java程序安装 打包_Java项目怎么打包成在windows下的可安装程序

    一:将项目文件导出成jar文件: 1,找到我们完成的项目代码,导出:(右键单击->Export) 2,选择java ->JAR file 下一步: 3,第一个不勾选,下一步: 4,选择ja ...

  8. 如何用Java制作hwid验证_java - 将帐户登录+ HWID锁定添加到Java程序的最安全方法是什么? - SO中文参考 - www.soinside.com...

    是的,你可以做到,但你需要重新设计你的应用程序.您应该将应用程序分成两个不同的应用程序.(简而言之:您还有很长的路要走) 1-客户端应用程序:Java应用程序与最终用户交互的位置. 2-服务器应用程序 ...

  9. 【程序猿历程】一个三年工作经验和月薪16k的java程序员应该要具备什么样的技能?

     

最新文章

  1. 比拼浮点运算速度,超算排行榜是这样“算”出来的
  2. 【转】itk、vtk、qt 显示dicom 数据
  3. springboot 接口404_资深架构带你学习Springboot集成普罗米修斯
  4. 求解九宫格的Java_使用全排列方法解九宫格问题
  5. python3.5安装scrapy_在Python3.5下安装和测试Scrapy爬网站
  6. base64位转成二进制流_你知道 Base64 编码中的 64 指的是什么吗?
  7. [Unity脚本运行时更新]C#4新特性
  8. Linux 密码复杂度
  9. python学习Day6 元组、字典、集合set三类数据用法、深浅拷贝
  10. 历史 微信开发者工具_微信开发者工具代码管理
  11. 使用promise封装ajax请求
  12. 如何在微信小程序内使用外部字体
  13. 诺基亚:丑小鸭的重生
  14. php 去逗号,php如何去除两边逗号
  15. 六轴UR机械臂正逆运动学求解_MATLAB代码(标准DH参数表)
  16. Lab3: 自行车码表
  17. 期末安卓习题--第七章
  18. windows下忘记mysql密码,跳过登录进入mysql解决方案
  19. DirectX12 之HelloWorld
  20. 雨天在火车站台上撑伞会触电吗?

热门文章

  1. R语言data.table导入数据实战:data.table使用字符向量创建新的数据列
  2. python秩和检验(Kruskal-Wallis H Test)
  3. 基于TF-IDF编码进行文本聚类分析:文档成对相似性计算、层次聚类(链接矩阵、树形图dendrogram绘制、聚类标签)
  4. 生信人的linux考试
  5. C#中struct和class的使用区别是什么?
  6. Assembly and diploid architecture of an individual human genome via single-molecule technologies
  7. 树莓派开发7-Pi摄像头+mjpg-streamer
  8. python 播放 wav 文件
  9. windows10下使用virtualenv虚拟技术,管理多个python版本,多个项目包环境
  10. 视频动作识别--Two-Stream Convolutional Networks for Action Recognition in Videos