zoukankan      html  css  js  c++  java
  • java虚拟机-内存的分配

        java虚拟机在执行java程序的过程中,把它管理的内存划分为若干个区域

    线程私有的:

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

    线程共享的:

    • 方法区
    • 直接内存

    1  程序计数器:
           程序计数器本质上是一块 较小 的内存空间,它可以看做是当前线程所执行的字节码的 行号指示器 ;在虚拟机的概念模型里(仅仅是概念模型,各种虚拟机可能会通过一些更高效的方式去实现),字节码解释器工作时,就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成 

    另外,为了线程上下文切换后能恢复到原来执行的位置,每个线程都需要一个独立的程序计数器,各线程之间计数器互不影响,独立存储,我们称这类内存区域为“线程私有”的内存。

    总结程序计数器的2个作用

    1.  字节码解释器通过改变程序计数器来依次读取指令,实现代码流程控制,如顺序执行,循环,选择,异常处理等

    2.  多线程情况下,程序计数器用于记录当前线程执行的位置,从而确保线程切换回来后知道该线程上次运行到哪儿

    注意:程序计数器是唯一一个不会出现OutOfMemoryError的内存区域,它的生命周期随着线程的创建而创建,随着线程的结束而死亡

    2 虚拟机栈 :

         Java 内存可以粗糙的区分为堆内存(Heap)和栈内存(Stack),其中栈就是现在说的虚拟机栈,
         里面存放的一个个栈帧,每个栈帧对应一个被调用的方法,
    栈帧中包括:局部变量表,操作数栈,指向运行时常量池的引用,动态链接、方法出口信息

    局部变量表: 主要存放了编译器可知的各种数据类型(boolean、byte、char、short、int、float、long、double)、

    对象引用(reference类型,它不同于对象本身,可能是一个指向对象起始地址的引用指针,也可能是指向一个代表对象的句柄或其他与此对象相关的位置)。
    栈帧的产生和消亡: 当线程执行一个方法时,就会随之创建一个对应的栈帧,并将之压栈,当执行完毕则出栈

    Java 虚拟机栈会出现两种异常:StackOverFlowError 和 OutOfMemoryError。

    • StackOverFlowError: 若Java虚拟机栈的内存大小不允许动态扩展,那么当线程请求栈的深度超过当前Java虚拟机栈的最大深度的时候,就抛出StackOverFlowError异常。
    • OutOfMemoryError: 若 Java 虚拟机栈的内存大小允许动态扩展,且当线程请求栈时内存用完了,无法再动态扩展了,此时抛出OutOfMemoryError异常。

    每个线程正在执行的方法可能不同,因此每个线程都有一个自己的java栈,互不干扰。

    3 本地方法栈:
        与虚拟机栈原理相似,区别是: 虚拟机栈为虚拟机执行 Java 方法 (也就是字节码)服务,

    而本地方法栈则为虚拟机使用到的 Native 方法服务

    4 java堆:
           java虚拟机所管理内存最大的一块,java堆是所有线程共享的一块内存区域,在虚拟机启动时创建,

    此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例以及数组都在这里分配内存

    java堆是java垃圾收集器管理的主要区域,因此也称为GC堆,从垃圾回收的角度,由于现在收集器基本都采用分代垃圾收集算法,

    所以Java堆还可以细分为:新生代和老年代:再细致一点有:Eden空间、From Survivor、To Survivor空间等。进一步划分的目的是更好地回收内存,

    或者更快地分配内存。

    在 JDK 1.8中移除整个永久代,取而代之的是一个叫元空间(Metaspace)的区域(永久代使用的是JVM的堆内存空间,

    而元空间使用的是物理内存,直接受到本机的物理内存限制)

    5 方法区:
         方法区内,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据,

    虽然Java虚拟机规范把方法区描述为堆的一个逻辑部分,但是它却有一个别名叫做 Non-Heap(非堆),目的应该是与 Java 堆区分开来。

    6  运行时常量池

        运行时常量池是方法区的一部分,class文件中不只有类的版本,字段,方法,接口等描述性信息外,

    还有常量池信息(用于存放编译期生成的各种字面量和符号引用

    既然运行时常量池时方法区的一部分,自然受到方法区内存的限制,当常量池无法再申请到内存时会抛出 OutOfMemoryError 异常。

    JDK1.7及之后版本的 JVM 已经将运行时常量池从方法区中移了出来,在 Java 堆(Heap)中开辟了一块区域存放运行时常量池。

    7 直接内存

        直接内存并不是虚拟机运行时数据区的一部分,也不是虚拟机规范中定义的内存区域,但是这部分内存也被频繁地使用。而且也可能导致 OutOfMemoryError 异常出现。

    JDK1.4中新加入的 NIO(New Input/Output) 类,引入了一种基于通道(Channel) 与缓存区(Buffer) 的 I/O 方式,它可以直接使用Native函数库直接分配堆外内存,然后通过一个存储在 Java 堆中的 DirectByteBuffer 对象作为这块内存的引用进行操作。这样就能在一些场景中显著提高性能,因为避免了Java 堆和 Native 堆之间来回复制数据。

    本机直接内存的分配不会收到 Java 堆的限制,但是,既然是内存就会受到本机总内存大小以及处理器寻址空间的限制。

  • 相关阅读:
    java忽略安全警告注解@SuppressWarnings
    spring data jpa 报for input String "id"错误解决
    spring Data Jpa 报错 failed to lazily initialize a collection of role: com.itheim.pojo.Role.users, could not initialize proxy
    记一次Content type 'application/json;charset=UTF-8' not supported解决方案
    包冲突异常 loader constraint violation: when resolving interface method "javax.servlet.jsp.JspApplicationContext.getExpressionFacto
    Java运算符(&)、(|)、(^)、(~)
    Java中的原码、补码、反码
    vim编辑器
    Linux yum、tar、rpm、zip、gzip命令的使用
    error Couldn't find a package.json file in
  • 原文地址:https://www.cnblogs.com/hup666/p/10468037.html
Copyright © 2011-2022 走看看