注意:本系列博客,主要参考自以下四本书

《分布式Java应用:基础与实践》《深入理解Java虚拟机(第二版)》《深入分析Java web技术内幕》《实战java虚拟机》

1、为什么要了解JVM内存管理机制

  • JVM自动的管理内存的分配与回收,这会在不知不觉中浪费很多内存,导致JVM花费很多时间去进行垃圾回收(GC)
  • 内存泄露,导致JVM内存最终不够用

2、JVM内存结构

根据上图,JVM内存结构包括:

  • 方法区 - Java虚拟机规范

    • <jdk8 之前的实现是永久代,java8里彻底被移除,取而代之的是元数据区
  • 栈(在hotspot JVM中,JVM方法栈--Java虚拟栈,与本地方法栈是同一个)
  • PC寄存器(程序计数器)

还有一块:

  • 直接内存:直接向系统内存申请的一块内存区域,javaNIO会使用,速度优于java堆内存。- 隶属于物理内存,不属于JVM内存

注意点:

  • 堆是GC的主要区域,方法区、直接内存也会发生GC
  • 栈与PC寄存器是每个线程都会创建的私有区域,不会GC
  • 直接内存使用速度由于堆内存,但是内存的申请速度低于堆内存

2.1、方法区

  • 存放内容(类的各种信息-包括属性和方法、类static属性、常量池)

    • 已经加载的类的信息(名称、修饰符等)
    • 类中的field信息
    • 类中的方法信息
    • 类中的static变量
    • 类中定义为final常量
    • 运行时常量池:编译器生成的各种字面量和符号引用(编译期)存储在class文件的常量池中,这部分内容会在类加载之后进入运行时常量池,class文件的常量池查看 第三章 类文件结构与javap的使用
  • 使用实例:反射,在程序中通过Class对象调用getName等方法获取信息数据时,这些信息数据来源于方法区。
  • 调节参数
    • -XX:PermSize:指定方法区的最小值,默认为16M
    • -XX:MaxPermSize:指定方法区的最大值,默认为64M
  • 所抛错误
    • 方法区域要使用的内存超过了其允许的大小时,抛出OutOfMemoryError
  • 内存回收的主要目标
    • 对类的卸载(这也是为什么很多企业使用velocity等模板引擎做前端而不是使用jsp的原因之一)
    • 针对常量池的回收
  • 总结
    • 一般而言,在企业开发中,-XX:PermSize==-XX:MaxPermSize
    • 通常,这个大小设置为256M就没问题了,当然还要根据自己的程序去预估,并在运行过程中去调整,这里以在Resin服务器中配置为例
      1. <jvm-arg>-XX:PermSize=256M</jvm-arg>
      2. <jvm-arg>-XX:MaxPermSize=256M</jvm-arg>
    • 类中的static变量会在方法区分配内存,但是类中的实例变量不会(类中的实例变量会随着对象实例的创建一起分配在堆中,当然若是基本数据类型的话,会随着对象的创建直接压入操作数栈)
    • 关于方法区的存放内容,可以这样去想所有的通过Class对象可以反射获取的都是从方法区获取的(包括Class对象也是方法区的,Class是该类下所有其他信息的访问入口)

注意:常量池在jdk1.6在方法区;在jdk1.7在堆

附:元数据区

  • 调节参数:-XX:MaxMetaspaceSize,如果不指定大小,极限情况下可能耗尽系统所有内存
  • 元数据区是堆外的一块直接内存

2.2、堆

  • 存放内容

    • 对象实例(类中的实例变量会随着对象实例的创建一起分配在堆中,当然若是基本数据类型的话,会随着对象的创建直接压入操作数栈),这一点查看 第四章 类加载机制
    • 数组值
  • 使用实例
    • 所有通过new创建的对象都在这块儿内存分配,具体分配到年轻代还是年老代需要根据配置参数而定(新建对象直接分配到年老代有两种情况,看下边)
  • 调节参数
    • -Xmx:最大堆内存,默认为物理内存的1/4但小于1G
    • -Xms:最小堆内存,默认为物理内存的1/64但小于1G
    • -XX:MinHeapFreeRatio,默认当空余堆内存小于最小堆内存的40%时,堆内存增大到-Xmx
    • -XX:MaxHeapFreeRatio,当空余堆内存大于最大堆内存的70%时,堆内存减小到-Xms
  • 注意点
    • 在实际使用中,-Xmx与-Xms配置成相等的,这样,堆内存就不会频繁的进行调整了
  • 抛出错误
    • OutOfMemoryError:在堆中没有内存完成实例分配(关于实例内存的分配,之后再说),此时堆内存已达到最大无法扩展时。
  • 堆内存划分

    • 新生代

      • 组成:Eden+From(S0)+To(S1)
      • -Xmn:整个新生代的大小
      • -XX:SurvivorRatio:调整Eden:From(To)的比率,默认为8:1
    • 年老代
      • 新建对象直接分配到年老代,两种情况

        • 大对象:-XX:PretenureSizeThreshold(单位:字节)参数来指定大对象的标准,在Parallel Scavenge GC下可能无效,具体见《第五章 JVM垃圾收集器(1) 》
        • 大数组:数组中的元素没有引用任何外部的对象
  • 总结
    • 企业开发中,-Xmx==-Xms
    • -Xmx的设置要根据自己的程序去预估,并在运行过程中去调整,这里以在Resin服务器中配置为例
      1. <jvm-arg>-Xms2048m</jvm-arg>
      2. <jvm-arg>-Xmx2048m</jvm-arg>
      3. <jvm-arg>-Xmn512m</jvm-arg>
      4. <jvm-arg>-XX:SurvivorRatio=8</jvm-arg>
      5. <jvm-arg>-XX:MaxTenuringThreshold=15</jvm-arg>

      可以看到,-Xms==-Xmx==2048m,年轻代大小-Xmn==512m,这样,年老代大小就是2048-512==1536m,这个比率值得记住,在企业开发中,年轻代:年老代==1:3,而此时,我们配置的-XX:MaxTenuringThreshold=15(这也是默认值),年轻代对象经过15次的复制后进入到年老代(关于这一点,在之后的GC机制中会说),

    • -XX:MaxTenuringThreshold与-XX:PretenureSizeThreshold不一样,不要看错

2.3、栈

  • 注意点

    • 每条线程都会分配一个栈,每个栈中有多个栈帧(每一个方法对应一个栈帧)
    • 线程创建的时候创建一个线程的java栈
    • 每个方法在执行的同时都会创建一个栈帧,每个栈帧用于存储当前方法的局部变量表、操作数栈等,具体查看本文第一个图,每一个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程,说的更明白一点,就是方法执行时创建栈帧,方法结束时释放栈帧所占内存
  • 存放内容
    • 局部变量表:八大基本数据类型数据、对象引用。该空间在编译期已经分配好,运行期不变。
    • 操作数栈:是执行引擎直接操作的部分
  • 调节参数
    • -Xss:设置栈的大小,通常设置为1m就好

      1. <jvm-arg>-Xss1m</jvm-arg>
  • 支持native方法执行(本地方法栈)
  • 所抛错误
    • StackOverFlowError:线程请求的栈深度大于虚拟机所允许的深度。

      • 栈的深度就是方法调用嵌套的层数,受限于-Xss的大小
      • 典型场景:没有终止条件的递归(递归基于栈)。
      • 每个方法的栈的深度在javac编译之后就已经确定了,查看 第三章 类文件结构与javap的使用
    • OutOfMemoryError:虚拟机栈可以动态扩展,如果扩展的时候无法申请到足够的内存。
      • 需要注意的是,栈可以动态扩展,但是栈中的局部变量表不可以。

2.4、PC寄存器(程序计数器)

  • 概念:当前线程所执行的字节码的行号指示器,用于字节码解释器对字节码指令的执行。
  • 多线程:通过线程轮流切换并分配处理器执行时间的方式来实现的,在任何一个时刻,一个处理器(也就是一个核)只能执行一条线程中的指令,为了线程切换后能恢复到正确的执行位置,每条线程都要有一个独立的程序计数器,各条线程之间计数器互不影响,独立存储。

附:对象分配(《实战java虚拟机》)

第一章 JVM内存结构的更多相关文章

  1. 第三章 JVM内存回收区域+对象存活的判断+引用类型+垃圾回收线程

    注意:本文主要参考自<深入理解Java虚拟机(第二版)> 说明:查看本文之前,推荐先知道JVM内存结构,见<第一章 JVM内存结构> 1.内存回收的区域 堆:这是GC的主要区域 ...

  2. 第二章 JVM内存分配

    注意:本篇博客,主要参考自以下四本书 <分布式Java应用:基础与实践> <深入理解Java虚拟机(第二版)> <突破程序员基本功的16课> <实战java虚 ...

  3. java的线程安全、单例模式、JVM内存结构等知识学习和整理

    知其然,不知其所以然 !在技术的海洋里,前路漫漫,我一直在迷失着自我. 欢迎访问我的csdn博客,我们一同成长! "不管做什么,只要坚持下去就会看到不一样!在路上,不卑不亢!" 博 ...

  4. 基于JDK1.8的JVM 内存结构【JVM篇三】

    目录 1.内存结构还是运行时数据区? 2.运行时数据区 3.线程共享:Java堆.方法区 4.线程私有:程序计数器.Java 虚拟机栈.本地方法栈 5.JVM 内存结构总结 在我的上一篇文章别翻了,这 ...

  5. 管中窥豹——从对象的生命周期梳理JVM内存结构、GC调优、类加载、AOP编程及性能监控

    如题,本文的宗旨既是透过对象的生命周期,来梳理JVM内存结构及GC相关知识,并辅以AOP及双亲委派机制原理,学习不仅仅是海绵式的吸收学习,还需要自己去分析why,加深对技术的理解和认知,祝大家早日走上 ...

  6. JVM内存结构,运行机制

    三月十号,白天出去有事情出去了一天,晚上刚到食堂就接到阿里电话, 紧张到不行,很多基础的问题都不知道从哪里说了orz: 其中关于JVM内存结构,运行机制,自己笔记里面有总结的,可当天还是一下子说不出来 ...

  7. JVM内存结构 JVM的类加载机制

    JVM内存结构: 1.java虚拟机栈:存放的是对象的引用(指针)和局部变量 2.程序计数器:每个线程都有一个程序计数器,跟踪代码运行到哪个位置了 3.堆:对象.数组 4.方法区:字节流(字节码文件) ...

  8. JVM(七):JVM内存结构

    JVM(七):JVM内存结构 在前几节的文章我们多次讲到 Class 对象需要分配入 JVM 内存,并在 JVM 内存中执行 Java 代码,完成对象内存的分配.执行.回收等操作,因此,如今让我们来走 ...

  9. jvm内存结构及对象漫谈(较全)

    最近想整理一下GC相关的知识和经验,在整理之前先整理一下jvm的内存结构,后续会持续更新. jvm内存结构重要由两部分组成:线程共享区域与线程私有区域,如下图所示: 其中方法区和堆为线程共享区域,栈与 ...

随机推荐

  1. select 中添加option的注意

    在平时写JS中经常要给Select添加option,如果我们把option中的数据用一个字符串来表示: eg: var strOption='<option>1</option> ...

  2. go语言channel的别样用法

    1.返回值使用通道 func main() { // 生成随机数作为一个服务 randService := randGenerator() // 从服务中读取随机数并打印 fmt.Printf(&qu ...

  3. python selenium点滴

    from selenium import webdriver from selenium.webdriver.common.keys import Keys driver = webdriver.Ch ...

  4. Spring AOP开发

    --------------------siwuxie095                                 Spring AOP 开发         1.在 Spring 中进行 ...

  5. 【原创】java删除未匹配的文件夹FileFileFilter,FileUtils,删除目录名字不是某个名字的所有文件夹及其子文件夹

    闲着无聊,写了个小程序. 需求: 举例: 比如我的E盘有一个test的目录,test的结构如下: 要求除了包含hello的目录不删除以外,其他的所有文件夹都要删除. 代码如下: package com ...

  6. 两个应用之间传递广播的规则 Broadcast

    sendBroadcast(new Intent(Config.ACTION_PRINT),”com.qf.permission.print”);先判断应用有没有对应的权限 再去判断有没有对应的act ...

  7. 批量去重URL地址并剔除打不开网址

    #coding=utf-8 import os import httplib import socket dictlist ={}; def ReadHost(): hosts = []; obn = ...

  8. PM2使用及介绍

    pm2 是一个带有负载均衡功能的Node应用的进程管理器.当你要把你的独立代码利用全部的服务器上的所有CPU,并保证进程永远都活着,0秒的重载, PM2是完美的.它非常适合IaaS结构,但不要把它用于 ...

  9. Linux wget命令

    一.简介 wget是一个Linux系统中的下载文件的工具,它用在命令行下.对于Linux用户是必不可少的工具,我们经常要下载一些软件或从远程服务器恢复备份到本地服务器.wget支持HTTP,HTTPS ...

  10. CreateMutex用法

    1.  CreateMutex只是创建了一把锁,  这把锁你用来锁门还是锁抽屉还是锁你对象的内裤都由你自己决定. 2. lpName是指定这把锁的名字.  你要不给这把锁取个名字都可以.  只是有了相 ...