jvm系列 (一) ---jvm内存区域与溢出

jvm内存区域与溢出

为什么学习jvm

  • 木板原理,最短的一块板决定一个水的深度,当一个系统垃圾收集成为瓶颈的时候,那么就需要你对jvm的了解掌握。
  • 当一个系统出现内存溢出,内存泄露的时候,因为你懂jvm知识,可以更加快速定位错误,可以通过参数去合理设置各内存区域的内存容量。
  • 因为你对jvm的认识,写代码的时候会潜意识地让你注意代码质量,可能你会说是那是小小的性能提升,但是量变会导致质变的。

jvm内存区域

jvm内存划分

  • 方法区
  • 虚拟机栈
  • 本地方法栈
  • 程序计数器

程序计数器

  • 当前线程所执行的字节码的行号指示器。
  • 因为cpu的每个核心只能同时运行一个线程,所以当一个线程执行完时间片后切换到另一个线程,切换时为了能恢复到正确的执行位置,所以需要程序计数器(学过计算机组成原理的应该比较熟悉)。
  • 如果是线程执行的是一个java方法那么此时计数器记录的是正在执行的虚拟机字节码指令的地址。如果是nativ方法(非java代码),计数器值为空。

虚拟机栈

  • java执行的内存模型,栈由栈帧组成,线程调用一个java方法时,创建一个栈帧,方法返回时,栈帧弹出。栈帧入栈出栈的过程就是方法开始结束的过程
  • 栈帧存储局部变量区(存放基本数据类型数据,对象指针),操作数栈(存放操作数,比如加法运算的时候操作数栈取值,计算后再压入栈),动态链接,方法出口。

本地方法栈

  • 和虚拟机栈作用类似,只不过服务对象不同,本地方法服务对象是非java方法,虚拟机栈服务对象是java方法

方法区

  • 存放类的信息、常量、静态变量等
  • 运行时常量池是方法区一部分,主要存放字面量(如final修饰的变量)和符号引用量(编译原理方面)

  • 存放对象,对象要在堆上分配内存
  • 堆分为年轻代和年老代
  • 年轻代分为伊甸区(Eden space)和幸存者区(Survivor space)
  • 幸存区分为from和to空间

总结

  • jvm的内存区域划分为程序计数器,虚拟机栈,本地方法栈,方法区,堆。
  • 程序计数器,虚拟机栈和本地方法栈都是线程独享的,而方法区和堆是线程共享的

溢出

理清概念

  • 操作系统分配给进程的内存是有限的,而jvm的内存区域我们已经知道,当我们设置好堆和方法区的最大容量后,那么剩下的内存将分配给虚拟机栈和本地方法区和程序计数器(占用内存少)。
  • 两种常见的溢出异常,一种OutOfMemoryError(OOM),一种StackOverflowError。

各区溢出情况

  • 堆溢出,当我们创建的对象占用的内存超过最大堆容量时候,会抛出OOM
  • 本地方法栈和虚拟机栈溢出:当请求的栈深度超过虚拟机所允许的深度的时候会抛出栈溢出,这种情况我们在使用递归出错的时候经常遇到;还有就是出现 OOM的情况,我们知道分配给这两个栈的内存是有限,和线程数和线程的栈内存有关系,那么当我们其中任意一个过大的话,都有可能造成OOM
  • 方法区和运行时常量池溢出:方法区存放类的信息,有时我们用的框架在动态代理的时候会动态生成CLASS,这个时候有可能会出现方法区的OOM; 而常量池溢出我们可以用String的intern方法(如果常量池没有与字符串相等的字符串,就将这个字符串存入方法区)进行模拟。

设置各区的jvm参数

  • 设置堆的最小值-Xms,堆的最大值-Xmx
  • 设置永久代(jdk8之前用永久代来实现方法区)的最小值-XX:PermSize ,最大值-XX:MaxPermSize
  • 设置栈容量-Xss

延伸

关于创建字符串

 String s2=new String("jiajun");
        String s6=new String("jiajun");
        System.out.println(s2==s6);
  • 结果为false,都存放在堆内存,但是两个地方。
        String s6=new String("jiajun");
        String s1="jiajun";
        System.out.println(s1==s6);
  • 结果为false,s6存放在堆当中,而s1存放在常量池当中
        String s1="jiajun";
        String s7="jiajun";
        System.out.println(s1==s7);
  • 结果为true,都是存放在常量池
        String s4="jia";
        String s5=s4+"jun";
        String s1="jiajun";

        System.out.println(s1==s5);
  • 结果为false,变量的值在运行的时候才确定,所以此时s5实际上是new一个对象
        String s3="jia"+"jun";
        String s1="jiajun";
        System.out.println(s1==s3);
  • 结果为true,此时s1 s3都是指向常量池一个string
        String s1="jiajun";
        String s8=new String("jia")+"jun";
        System.out.println(s1==s8);
  • 结果为false,此时s8同样是new出来一个对象
时间: 2024-10-12 12:33:37

jvm系列 (一) ---jvm内存区域与溢出的相关文章

jvm系列(八):jvm知识点总览-高级Java工程师面试必备

在江湖中要练就绝世武功必须内外兼备,精妙的招式和深厚的内功,武功的基础是内功.对于武功低(就像江南七怪)的人,招式更重要,因为他们不能靠内功直接去伤人,只能靠招式,利刃上优势来取胜了,但是练到高手之后,内功就更主要了.一个内功低的人招式在奇妙也打不过一个内功高的人.比如,你剑法再厉害,一剑刺过来,别人一掌打断你的剑,你还怎么使剑法,你一掌打到一个武功高的人身上,那人没什么事,却把你震伤了,你还怎么打.同样两者也是相辅相成的,内功深厚之后,原来普通的一招一式威力也会倍增. 对于搞开发的我们其实也是

[转]JVM系列三:JVM参数设置、分析

[转]JVM系列三:JVM参数设置.分析 不管是YGC还是Full GC,GC过程中都会对导致程序运行中中断,正确的选择不同的GC策略,调整JVM.GC的参数,可以极大的减少由于GC工作,而导致的程序运行中断方面的问题,进而适当的提高Java程序的工作效率.但是调整GC是以个极为复杂的过程,由于各个程序具备不同的特点,如:web和GUI程序就有很大区别(Web可以适当的停顿,但GUI停顿是客户无法接受的),而且由于跑在各个机器上的配置不同(主要cup个数,内存不同),所以使用的GC种类也会不同(

JVM学习系列(一) JAVA内存区域和内存溢出异常

JAVA内存区域介绍 程序计数器: 线程私有,很小的内存空间,可以看做是当前线程所执行的字节码的行号指示器: 每个线程都有一个独立的程序计数器,各个线程之间的计数器相互不影响,独立存储: 如果线程执行的是Java 方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址,如果是一个Native方法,那么这个计数器的值则为undefined: 该内存区域不会发生任何的OutOfMemoryError的情况(JAVA虚拟机规范中未规范). goto 保留字(Java当前版本暂且不用,也不让别人用),

JVM系列之六:内存溢出、内存泄漏 和 栈溢出

1. OOM && SOF OutOfMemoryError异常: 除了程序计数器外,虚拟机内存的其他几个运行时区域都有发生OutOfMemoryError(OOM)异常的可能, 内存泄露:指程序中动态分配内存给一些临时对象,但是对象不会被GC所回收,它始终占用内存.即被分配的对象可达但已无用. 内存溢出:指程序运行过程中无法申请到足够的内存而导致的一种错误.内存溢出通常发生于OLD段或Perm段垃圾回收后,仍然无内存空间容纳新的Java对象的情况. 从定义上可以看出内存泄露是内存溢出的一

JVM性能优化系列-(1) Java内存区域

1. Java内存区域 1.1 运行时数据区 Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域.主要包括:程序计数器.虚拟机栈.本地方法栈.Java堆.方法区(运 行时常量池).直接内存. 程序计数器 程序计数器(Program Counter Register)是一块较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器.在虚拟机概念模型中,字节码解释器工作时就是通过改变计数器的值来选取下一条需要执行的字节码指令,分支.循环.跳转.异常处理.线程恢复等

JVM解读:Java内存区域

JVM全称是java Virtual Machine(java虚拟机),JVM屏蔽了与各个计算机平台相关的软件和硬件差异. 在接下来的日子里,通过写博客的形式学习JVM,让自己更懂得Java! 本系列文章是对<深入分析javaweb技术内幕>和<深入理解java虚拟机>的总结,欢迎大家一起吐槽,一起进步. <JVM解读>第一篇:JVM体系结构 <JVM解读>第二篇:JVM类加载器ClassLoader 人人都知道的java的一大优点就是不需要程序员去显示的分

【深入理解JVM】:Java内存区域

JVM具有自动内存管理机制,Java不需要像c/c++一样,为每一个new操作写配对的delete/free代码,不容易出现内存泄露和溢出.JVM内存区域主要包括如下部分:程序计数器.Java虚拟机栈.本地方法栈.Java堆.方法区. 程序计数器 程序计数器可以视为当前线程所执行的字节码行号指示器,如果当前执行的是Native方法,计数器的值为空(Undefined).在JVM的概念模型中,字节码解释器通过改变计数器的值来选取下一条需要执行的字节码指令,分支.循环.跳转.异常处理.线程回复等都依

【搞定Jvm面试】 Java 内存区域揭秘附常见面试题解析

本文已经收录自笔者开源的 JavaGuide: https://github.com/Snailclimb ([Java学习+面试指南] 一份涵盖大部分Java程序员所需要掌握的核心知识)如果觉得不错的还,不妨去点个Star,鼓励一下! Java 内存区域详解 如果没有特殊说明,都是针对的是 HotSpot 虚拟机. 写在前面 (常见面试题) 基本问题 介绍下 Java 内存区域(运行时数据区) Java 对象的创建过程(五步,建议能默写出来并且要知道每一步虚拟机做了什么) 对象的访问定位的两种

jvm系列(二):JVM内存结构

原文出处:纯洁的微笑 所有的Java开发人员可能会遇到这样的困惑?我该为堆内存设置多大空间呢?OutOfMemoryError的异常到底涉及到运行时数据的哪块区域?该怎么解决呢?其实如果你经常解决服务器性能问题,那么这些问题就会变的非常常见,了解JVM内存也是为了服务器出现性能问题的时候可以快速的了解那块的内存区域出现问题,以便于快速的解决生产故障. 先看一张图,这张图能很清晰的说明JVM内存结构布局. JVM内存结构主要有三大块:堆内存.方法区和栈.堆内存是JVM中最大的一块由年轻代和老年代组