2.0引-Java内存区域中,栈内存和堆内存分别装什么,为什么?

  • 栈:解决程序的运行问题,即程序如何执行,或者说如何处理数据。
  • 堆:解决的是数据存储的问题,即数据怎么放,放在哪儿。

参考链接https://www.cnblogs.com/gdufs/p/6407432.html

2.2运行时数据区

线程隔离的运行时数据区:程序计数器、Java虚拟机栈、本地方法栈

  • 程序计数器:当前线程所执行的字节码的行号指示器,由于线程私有,故借助程序计数器线程切换后能恢复到正确的执行位置。
  • Java虚拟机栈:每个方法在执行时会创建一个栈帧。每一个方法从调用至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。
  • 本地方法栈 ?todo

线程共享的运行时数据区:Java堆、方法区(其中包含运行时常量池)

  • Java堆:存放对象实例。是垃圾收集器管理的主要区域。
  • 方法区:存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。?
  • 运行时常量池:是方法区的一部分。?todo

此外,直接内存不属于运行时数据区,但它也可能会产生内存溢出。Java中NIO类可以直接分配堆外内存。

2.3(基于HotSpot虚拟机)对象

对象的创建步骤

  • step1:类加载。new指令的符号参数在常量池定位到类的符号引用,检查这个符号引用代表的类是否被加载、解析、初始化过,没有的话首先进行类加载。
  • step2:为新对象分配内存。
    • 问题一:如何划分可用空间:

      • 方法一:指针碰撞。如果虚拟机堆中的内存是规整的,则把堆空闲内存指针移对象大小等大小距离即可。
      • 方法二:空闲列表。如果堆内存不规整,就要维护一个空闲列表记录空闲的内存块。
    • 问题二:修改指针所指向的位置,如何在并发情况下保证此操作是线程安全的。
      • 方法一:对分配内存空间的动作进行同步:虚拟机采用CAS?+失败重试的方式保证更新操作的原子性。
      • 方法二:本地线程分配缓冲(TLAB):即每个线程预先在队中分配一小块内存,是内存分配的动作在不同空间进行。只需在分配新TLAB时,进行同步锁定。选择是要用TLAB可通过参数-XX:+/-UseTLAB设定。
  • step3:将分配到的内存空间初始化为零值。
  • step4:对对象进行必要的设置。包括这个对象是哪个类的实例等。
  • step5:从虚拟机角度,step1-4完成了对象的创建。但从Java程序视角来看,还需要对对象进行初始化(init方法)。

对象的内存布局

HotSpot虚拟机中,对象内存存储=对象头(Mark Word)+实例数据+对齐填充。

其中,对象头包含哈希码、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳。它是一个非固定的数据结构,根据对象的状态复用自己的存储空间。

对象的访问定位

  • 两种,一种是通过句柄访问对象,一种是通过直接指针访问对象。

    • 通过句柄访问对象:Java堆中划分出一块内存作为句柄池,reference中存储的是对象的句柄地址,句柄中包含了对象实例数据地址(位于Java堆)及对象类型数据地址(位于方法区)
    • 通过直接指针访问对象:reference中存储的就是对象地址,对象中包括:对象类型数据指针(位于Java堆)+对象实例数据(位于方法区)。
  • 对比
    • 不同点:就是reference存储的是什么、Java堆中是否有句柄池、对相关类型数据的地址存在句柄池还是对象的对象头中。
    • 各自优势:句柄方式:reference中存储的是稳定的句柄地址,当对象被移动reference本身不需要修改;直接指针方式:快,节省了一次指针定位的开销。 - HotSpot使用直接指针访问方式。

2.4OutOfMemoryError异常

虚拟机内存除程序计数器外的其他几个运行时区域都可能发生OutOfMemoryError(OOM)异常。

2.4.1Java堆溢出

  • 产生堆溢出:当把堆设置为不自动扩展(设置堆最小值-Xms参数=堆最大值参数-Xmx参数)时,不断创建对象,并且保证GC Roots到对象之间有可达路径来避免垃圾回收机制清除这些对象,那么创建的所有对象超过堆的容量限制后,就会产生OutOfMemoryError异常。
  • 排查方法
    • 步骤1 通过内存映象分析工具对Dump出来的堆转储快照?进行分析,重点是确认是内存泄漏(指内存中有许多不必要对象)还是内存溢出(内存中的对象都是有必要的)。
    • 步骤2 如果是内存泄漏:通过工具,查看泄漏对象到GC Roots的引用链,就可以较准确地定位泄露代码的位置。
    • 如果是内存溢出:在物理内存允许的情况下,调大虚拟机的堆参数;此外,检查代码中睡否某些对象生命周期过长,持有状态时间过长?。

2.4.2虚拟机栈和本地方法栈溢出

  • 虚拟机参数:HosSpot虚拟机不区分虚拟机栈和本地方法栈,所以-Xoss参数(设置本地方法栈大小)是无效的。栈容量只由-Xss参数控制。

  • 关于虚拟机栈和本地方法栈,Java虚拟机规范描述了两种异常:已使用的栈空间太大:StackOverflowError;内存太小:OutOfMemoryError。但是这本质是对同一件事情的两种描述而已。

  • 由栈内存原因产生StackOverflowError异常

    • 单线程下:方法一:减少栈内存容量。方法二:定义大量本地变量。单线程下,经测试这两种方法均抛出StackOverflowError异常。
  • 产生OutOfMemoryError异常

    • 多线程下:通过不断建立线程产生OutOfMemoryError(内存溢出)异常,但这与栈内存容量是否足够大并无关联。事实上,反而每个线程分配的栈内存越大,越容易造成OutOfMemoryError异常。因为OS给每个进程分配的内存(瓜分给:Xmx最大堆容量+MaxPermSize最大方法区容量+最大栈容量(包括虚拟机栈和本地方法栈)+程序计数器占用的(较小,可忽略不计)+虚拟机进程本身耗费的(暂略))是有限制的,所以若每个线程分配的栈内存越大,可以建立的线程数就越少,就越容易在建立线程时把内存耗尽。
  • 排查方法

    • 针对StackOverflowError,可以阅读错误堆栈,找到问题所在。
    • 多线程下,针对OutOfMemoryError,在不能减少线程数或更换64位虚拟机的情况下,则可以通过减少最大堆容量和减少栈容量来换取更多线程

2.4.3方法区和运行时常量池溢出

  • 方法区:

    • 造成内存溢出:生成大量类。主流框架当有大量类增强,就可能会造成内存溢出。方法区溢出是常见的内存溢出异常,因为一个类被判定回收的条件非常苛刻。
    • 需要注意方法区溢出的场景:动态生成大量类;使用CGLib字节码增强;动态语言;大量JSP的应用;基于OSGi的应用。
  • 方法区中的运行时常量池:
    • 造成内存溢出:JDK1.6中,String.intern()不断建立常量,且保持引用保证不被GC,会造成内存溢出。JDK1.7以后String.intern()使用引用的方法,不再复制,不会造成内存溢出。
    • 排查方法:JDK1.6中,异常会提示OutOfMemoryError:PermGen space,说明是(HotSpot虚拟机)永久代的异常。JDK1.7后开始逐步“去永久代”。

2.4.4 本机直接内存溢出

  • 参数: -XX:MaxDirectMemorySize 指定,否则默认与Java堆最大值一样。
  • 排查方法:Heap Dump文件? 不会看到明显异常,如果发现OutOfMemoryError后Dump文件很小,程序中又使用了NIO,可以考虑是否是本机直接内存溢出。

[深入理解JVM虚拟机]第2章-Java内存区域与内存溢出异常的更多相关文章

  1. [深入理解JVM虚拟机]第3章-垃圾收集器、内存分配策略

    垃圾收集器 判断对象是否需存活 回收堆 判断对象是否存活: 方法一:引用计数法.对象被引用一次就+1,当为0时回收对象.缺点:无法解决循环引用问题. 方法二:可达性分析算法.记录当前对象是否有和GC ...

  2. 深入理解JVM虚拟机11:Java内存异常原理与实践

    本文转自互联网,侵删 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutori ...

  3. Java工程师学习指南第6部分:深入理解JVM虚拟机

    本文整理了微信公众号[Java技术江湖]发表和转载过的JVM虚拟机相关优质文章,想看到更多Java技术文章,就赶紧关注本公众号吧吧. JVM原理分析,看了都说好 JVM 深入学习:Java 解析 Cl ...

  4. 《深入理解java虚拟机》第二章 Java内存区域与内存溢出异常

    第二章 Java内存区域与内存溢出异常 2.2 运行时数据区域  

  5. 深入理解java虚拟机-第二章:java内存区域与内存泄露异常

    2.1概述: java将内存的管理(主要是回收工作),交由jvm管理,确实很省事,但是一点jvm因内存出现问题,排查起来将会很困难,为了能够成为独当一面的大牛呢,自然要了解vm是怎么去使用内存的. 2 ...

  6. 深入理解java虚拟机系列(一):java内存区域与内存溢出异常

    文章主要是阅读<深入理解java虚拟机:JVM高级特性与最佳实践>第二章:Java内存区域与内存溢出异常 的一些笔记以及概括. 好了開始.假设有什么错误或者遗漏,欢迎指出. 一.概述 先上 ...

  7. 《深入理解JVM虚拟机》读书笔记

    前言:<深入理解JVM虚拟机>是JAVA的经典著作之一,因为内容更偏向底层,所以之前一直没有好好的阅读过.最近因为刚好有空,又有了新目标.所以打算和<构架师的12项修炼>一起看 ...

  8. 深入理解JVM虚拟机1:JVM内存的结构与消失的永久代

    本文转自互联网,侵删 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutori ...

  9. 虚拟机--第二章java内存区域与内存溢出异常--(抄书)

    这是本人阅读周志明老师的<深入理解Java虚拟机>第二版抄写的,有很多省略,不适合直接阅读,需要阅读请出门左转淘宝,右转京东,支持周老师(侵权请联系删除) 第二章java内存区域与内存溢出 ...

随机推荐

  1. 设计模式详解及Python实现

    设计模式及Python实现 设计模式是什么? Christopher Alexander:"每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的解决方案的核心*.这样你就能一次又一 ...

  2. 【luogu4137】 Rmq Problem / mex - 莫队

    题目描述 有一个长度为n的数组{a1,a2,…,an}.m次询问,每次询问一个区间内最小没有出现过的自然数. 思路 莫队水过去了 233 #include <bits/stdc++.h> ...

  3. linux 查找删除

    find -name "*.php" -exec rm -f '{}' \;

  4. 计算机网络-应用层(1)Web应用与HTTP协议

    Web 页面(Web page,也叫文档)是由对象组成的. 对象:HTML文件.JPEG图片.视频文件.动态脚本等,通过一个URL地址寻址.每个URL地址由存放对象的服务器主机名和对象的路径名组成. ...

  5. 第三篇 Scrum冲刺博客

    一.会议图片 二.项目进展 成员 完成情况 今日任务 冯荣新 商品列表,商品详情轮播图 商品底部工具栏,购物车列表 陈泽佳 历史足迹,静态页面 渲染搜索结果,防抖的实现 徐伟浩 未完成 商品信息录入 ...

  6. SPSSAU新功能上线:高级公式、综合得分一键计算!

    一直关注我们的朋友们一定会发现,近期SPSSAU增添了很多新功能. 我们精挑细选出6个最常使用的功能,介绍给大家,看看这些新功能你有没有解锁成功呢? 01 一键删除无效样本 “无效样本”功能中,添加了 ...

  7. Shell编程—创建函数

    1基本的脚本函数 函数是一个脚本代码块,你可以为其命名并在代码中任何位置重用.要在脚本中使用该代码块时,只要使用所起的函数名就行了. 1.1创建函数 有两种格式可以用来在bash shell脚本中创建 ...

  8. wordpress个人常用标签调用

    wordpress常见标签调用,老是容易忘记,又要找半天,干脆搬到网站上. <?php bloginfo('name');?>网站名称 url <?php echo home_url ...

  9. java23种设计模式——六、适配器模式

    @ 目录 介绍 应用场景 优缺点 模式实现 源码在我的github和gitee中获取 介绍 适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁.这种类型的设计模式属于结构型模 ...

  10. 新手学习seo写原创文章的方法

    http://www.wocaoseo.com/thread-102-1-1.html 前两天都是写自己公司克拉玛依电信公司年终活动和总结的事,今天继续学习seo技术,其实说难也难说容易也容易,关键的 ...