深入理解jvm之内存区域与内存溢出

文章目录

  1. 1. Java内存区域与内存溢出异常

    1. 1.1. 运行时数据区域

      1. 1.1.1. 程序计数器
      2. 1.1.2. java虚拟机栈
      3. 1.1.3. 本地方法栈
      4. 1.1.4. Java堆(Java Heap)
      5. 1.1.5. 方法区
      6. 1.1.6. 运行时常量池
      7. 1.1.7. 直接内存
    2. 1.2. HotSpot虚拟机
      1. 1.2.1. 对象的创建
      2. 1.2.2. 对象的访问定位
    3. 1.3. OOM异常的解决思路
    4. 1.4. 参考

Java内存区域与内存溢出异常

运行时数据区域

程序计数器

  • 当前线程所执行的字节码的行号指示器
  • 当前线程私有
  • 不会出现OutOfMemoryError情况

java虚拟机栈

  • 线程私有,生命周期与线程相同
  • java方法执行的内存模型,每个方法执行的同时都会创建一个栈帧,存储局部变量表(基本类型、对象引用)、操作数栈、动态链接、方法出口等信息
  • StackOverflowError异常:当线程请求的栈深度大于虚拟机所允许的深度
  • OutOfMemoryError异常:如果栈的扩展时无法申请到足够的内存

本地方法栈

与虚拟机栈相似,主要为虚拟机使用到的Native方法服务,在HotSpot虚拟机中直接把本地方法栈与虚拟机栈二合一

Java堆(Java Heap)

java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。此区域的唯一目的就是存储对象实例。java堆是垃圾收集器管理的主要区域。java堆还可以细分为:新生代与老年代。在细一点有Eden空间、Form Survivor空间、To Survivor空间等。

  • 可以通过-Xmx和-Xms控制堆的大小
  • OutOfMemoryError异常:当在堆中没有内存完成实例分配,且堆也无法再扩展时。

方法区

  • 线程间共享
  • 用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据
  • OutOfMemoryError异常:当方法区无法满足内存的分配需求时

运行时常量池

  • 方法区的一部分
  • 用于存放编译期生成的各种字面量与符号引用
  • OutOfMemoryError异常:当常量池无法再申请到内存时

直接内存

  • NIO可以使用Native函数库直接分配堆外内存,堆中的DirectByteBuffer对象作为这块内存的引用进行操作
  • 大小不受Java堆大小的限制,受本机(服务器)内存限制
  • OutOfMemoryError异常:系统内存不足时

HotSpot虚拟机

对象的创建

虚拟机遇到一条new指令时,首先将去检查这个对象的参数是否在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载、解析和初始化过。如果没有,必须先执行类的加载过程。
在类加载检查通过后,虚拟机将为新生对象分配内存。对象所需内存大小再类加载完成后便可确定。内存分配可以采用“指针碰撞”与“空闲列表”的方式。

对象的访问定位

java程序需要通过栈上的reference数据来操作堆上的具体对象。访问方式有使用句柄和直接指针两种。

  • 句柄访问 java堆中将会划分出一块内存来作为句柄池,reference中存储的就是对象的句柄地址,而句柄中包含了对象实例数据与类型数据各自的具体地址信息
  • 直接指针访问 java堆对象的布局中必须考虑如何放置访问类型数据的相关信息,reference中存储的就是对象地址

OOM异常的解决思路

生成Dump快照文件:

  • 通过jvm参数—XX:-HeapDumpOnOutOfMemoryError可以让JVM在出现内存溢出是Dump出当前的内存转储快照
  • 用jmap生产dump文件,win通过任务管理器查看tomcat的进程pid,linux用ps命令查看进程pid,然后用jmap命令

先通过内存映像分析工具(如Eclipse的Memory Analyzer)进行分析,常见的情况有:

  • 内存泄露,对象已经死了,无法通过垃圾收集器进行自动回收,通过找出泄露的代码位置和原因,才好确定解决方案;
  • 内存溢出,内存中的对象都还必须存活着,这说明Java堆分配空间不足,检查堆设置大小(-Xmx与-Xms),检查代码是否存在对象生命周期太长、持有状态时间过长的情况。

OOM异常示例:

12345678910111213141516171819202122
package oom;

import java.util.ArrayList;import java.util.List;

/** * VM Args: -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError* @ClassName: HeapOOM * */public class HeapOOM {    static class OOMObject{

    }

    public static void main(String[] args) {        List<OOMObject> list = new ArrayList<OOMObject>();        while(true){            list.add(new OOMObject());        }    }}

参考

《深入理解java虚拟机 JVM高级特性与最佳实践》

时间: 2024-10-03 19:17:27

深入理解jvm之内存区域与内存溢出的相关文章

深入理解JVM之JVM内存区域与内存分配

深入理解JVM之JVM内存区域与内存分配 在学习jvm的内存分配的时候,看到的这篇博客,该博客对jvm的内存分配总结的很好,同时也利用jvm的内存模型解释了java程序中有关参数传递的问题. 博客出处: http://www.cnblogs.com/hellocsl/p/3969768.html?utm_source=tuicool&utm_medium=referral 看了此博客后,发现应该去深入学习下jvm的内存模型,就是去认真学习下<深入理解Java虚拟机>,其内容可能会<

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

文章主要是阅读<深入理解java虚拟机:JVM高级特性与最佳实践>第二章:Java内存区域与内存溢出异常 的一些笔记以及概括. 好了开始.如果有什么错误或者遗漏,欢迎指出. 一.概述 先上一张图 这张图主要列出了Java虚拟机管理的内存的几个区域. 常有人把Java内存区分为堆内存(Heap)和栈内存(Stack),这种分法比较粗糙,Java内存区域的划分实际上远比这复杂,从上图就可以看出了.堆栈分法中所指的"栈"实际上只是虚拟机栈,或者说是虚拟机栈中的局部变量表部分.接下

《深入理解Java虚拟机》读书笔记---第二章 Java内存区域与内存溢出异常

Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的高墙,墙外面的人想进去,墙里面的人却想出来.这一章就是给大家介绍Java虚拟机内存的各个区域,讲解这些区域的作用,服务对象以及其中可能产生的问题. 1.运行时数据区域 Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域. 1.1程序计数器 程序计数器(Program Counter Register)是一块较小的内存空间,它的作用可以看作是当前线程所执行的字节码的行号指示器.在虚拟机的概念模型中里,字

Java内存区域与内存溢出异常-内存区域

Java内存区域与内存溢出异常 概述 对于 C 和 C++程序开发的开发人员来说,在内存管理领域,程序员对内存拥有绝对的使用权,但是也要主要到正确的使用和清理内存,这就要求程序员有较高的水平. 而对于 Java 程序员来说,在虚拟机的自动内存管理机制的帮助下,不再需要为每一个 new 操作去写配对的 delete/free 代码,而且不容易出现内存泄漏和内存溢出问题,看起来由虚拟机管理内存一切都很美好.不过,也正是因为 Java 程序员把内存控制的权力交给了 Java 虚拟机,一旦出现内存泄漏和

图解Java内存区域及内存溢出异常

图解 Java 内存区域及内存溢出异常 在阅读 <深入理解Java虚拟机:JVM高级特性与最佳实践(第2版) >后,为了加深对 Java 内存区域的印象及理解,特意做成了思维导图. 名词解释 线程共享数据区域 直接内存 并不是虚拟机运行时数据区的一部分,也不是 Java 虚拟机规范中定义的内存区.NIO 中使用 Native 函数直接分配堆外内存 方法区 Method Area 用于存放已被虚拟机加载的类信息.常量.静态变量.JIT 编译后的代码等 也称作 永久代,在这块容易遇到 OOM 问题

深入了解Java虚拟机(1)java内存区域与内存溢出异常

java内存区域与内存溢出异常 一.运行时数据区域 1.程序计数器:线程私有,用于存储当前所执行的指令位置 2.Java虚拟机栈:线程私有,描叙Java方法执行模型:执行方法时都会创建一个栈帧,存储局部变量,基本类型变量,引用等信息 3.Java本地方法栈:线程私有,为虚拟机使用到的Native方法服务 4.Java堆:线程共享,是垃圾收集器的主要工作地方:存储对象实例等 5.方法区:线程共享:存储类信息,常量,静态变量等 运行时常量:存放编译时生成的各种字面量和符号引用 6.直接内存:机器的内

【深入Java虚拟机】之一:Java内存区域与内存溢出

[深入Java虚拟机]之:Java内存区域与内存溢出 内存区域 Java虚拟机在执行Java程序的过程中会把他所管理的内存划分为若干个不同的数据区域.Java虚拟机规范将JVM所管理的内存分为以下几个运行时数据区:程序计数器.Java虚拟机栈.本地方法栈.Java堆.方法区.下面详细阐述各数据区所存储的数据类型. 程序计数器(Program Counter Register) 一块较小的内存空间,它是当前线程所执行的字节码的行号指示器,字节码解释器工作时通过改变该计数器的值来选择下一条需要执行的

2.1 自动内存管理机制--Java内存区域与内存溢出异常

自动内存管理机制 第二章.Java内存区域与内存溢出异常 [虚拟机中内存如何划分,以及哪部分区域.什么样代码和操作会导致内存溢出.各区域内存溢出的原因] 一.运行时数据区域 Java虚拟机所管理的内存包括以下几个运行时数据区域[虚拟机内存模型]: 1.程序计数器: 可以看作是当前线程所执行的字节码的行号指示器.在虚拟机中,字节码解释器工作时就是通过程序计数器的值来选择下一条需要执行的字节码指令.Java虚拟机中多线程是通过线程轮流切换并分配处理机执行时间的方式实现的,在任何一个确定的时刻,一个处

深入理解JVM读书笔记一: Java内存区域与内存溢出异常

Java虚拟机管理的内存包括几个运行时数据内存:方法区.虚拟机栈.本地方法栈.堆.程序计数器,其中方法区和堆是由线程共享的数据区,其他几个是线程隔离的数据区. 2.2 运行时数据区域 2.2.1程序计数器 程序计数器是一块较小的内存,他可以看做是当前线程所执行的行号指示器.字节码解释器工作的时候就是通过改变这个计数器的值来选取下一条需要执行的字节码的指令,分支.循环.跳转.异常处理.线程恢复等基础功能都需要依赖这个计数器来完成.如果线程正在执行的是一个Java方法,这个计数器记录的是正在执行的虚