zoukankan      html  css  js  c++  java
  • JVM内存区域简介

    前言

    ​ 在Java运行期,程序会使用到若干内存区,其中一些会随着虚拟机启动而创建,随着虚拟机销毁而销毁。还有些则是与线程一一对应,他们随着线程的开始而创建,线程的结束而销毁。

    • Jvm运行时内存区根据生命周期分为2种:1、归属虚拟机的。2、归属线程的。
    • 线程描述:开始和结束;内存描述:创建和销毁。

    《Java虚拟机规范》(Java SE8 版)第二章第五节规定以下内存区:pc寄存器、Java虚拟机栈、Java堆、方法区、运行时常量池、本地方法栈。

    Java内存区域

    1、程序计数器

    ​ 在虚拟机规范中:pc(program counter)寄存器用来保存线程的当前方法

    ​ Java允许多线程执行,每个线程都有自己的计数器,它保存当前线程的执行位置。Java多线程是通过线程轮流切换来并分配处理器执行时间的方式运行(在单核硬件系统中,所有的多线程都是如此运行,例如计算机的cpu时间)。一个处理器每时每刻都只能处理一条线程的任务,所有当多线程切换时,通过pc计数器来记住当前的位置。

    • pc计数器属于线程的,每个线程都有自己的计数器。
    • 各个线程计数器之间互不影响,独立存储。
    • pc计数器用来记住线程执行的当前位置

    2、Java虚拟机栈

    ​ 虚拟机规范中:Java虚拟机栈(stack)用于保存栈帧

    栈帧:方法运行时的基础数据结构;用于存储局部变量表、操作数栈、动态链接、方法出口信息等。

    ​ 虚拟机栈只收到栈帧的出入影响,我们很容易知道栈的运行模式时"后入先出"。JVM对于栈的实现中,操作的元素是栈帧。它在内存区中是允许连着堆内存,但它属于线程,操作的元素是"栈帧",所以堆(heap)和栈(stack)的区分在于他们的功能而不是内存位置。

    • 栈中操作的数据元素是栈帧
    • 内存可以跟堆连续或者在堆中分配。
    • 虚拟机栈是属于线程的。

    关于栈ADT。栈其实是后入先出表;在Java中可以用数组或者表来实现。

    关于栈帧一。栈帧的数据结构中,最主要的是操作数栈,它是栈的标准实现,是一个后入先出的表。在条件允许的情况下,我们通常称呼"当前栈帧的操作数栈" 为 "操作数栈"

    关于栈帧运行原理:每个线程正在处理的栈帧成为"当前栈帧",它的方法称为"当前方法",它的类称为"当前类"。当一个方法创建时,创建它的栈帧,方法结束或者调用新的方法时,新的栈帧随之创建,作为新的"当前栈帧",直到最后方法执行完成,将得到的结果返回给前一个栈帧。使得前一个栈帧重新称为"当前栈帧"。

    3、本地方法栈

    ​ 虚拟机规范中:本地方法栈用来支持native方法。如果虚拟机不允许native方法,或者本身不依赖传统栈,可以不实现本地方法栈。

    4、Java堆

    ​ 虚拟机规范中:Java堆保存线程所共有的数据;堆的实现不要求内存区域上是连续的。

    ​ 虚拟机规范中:所有对象实例都要在堆上分配。

    ​ 堆的占比在Java程序中是最大的一部分,随着jvm的启动而创建,保存着线程所共有的信息,例如:对象信息,在大型系统中,对象有可能会有很多!甚至有些程序会在短时间内创建大量的对象。所以堆内存的管理和优化也是很重要的,jvm的垃圾回收算法(C程序开发者最烦内存管理?C程序员最喜欢自己整理内存?)也在不断的升级,就是为了能够更好的管理堆内存,防止出现outOfMemoryError异常。

    • 堆内存是属于jvm的
    • 堆内存中保存对象实例信息
    • 堆内存被gc管理

    堆和栈是很多新手小兄弟都会了解但是又一知半解的。推荐下如何正确理解Java堆栈:

    1. 了解栈数据结构;

    2. 了解堆数据结构;

    3. 区分堆内存和堆数据结构;

    4. 了解堆内存和栈内存的联系和区别。

    (嗯... 也比较好理解)

    5、方法区

    ​ 虚拟机规范中:不限定实现方法区的内存位置和编译代码的管理策略

    ​ 虚拟机规范中:方法区保存的也是线程所共有的数据,存储类的结构信息。包括:运行时常量池、字段、方法数据、构造函数和普通方法的字节码内容。

    • 方法区随着jvm的启动而创建
    • 不同的jvm对于方法区有着不同的理解和实现
    • HotSpot (jdk默认) 虚拟机将gc的管理范围扩散到方法区,作为永久代的实现。

    方法区这个内存块在很多地方有不同的实现,它的最主要的功能是存放类的结构信息。包括:运行时常量池、字段、方法数据、构造函数和普通方法的字节码。

    可以将方法区跟堆内存相连,直接采用堆中的gc来管理方法区内存;也可以单独划出一部分内存作为方法区,并单独写一套内存管理方法;不同的虚拟机允许不同的实现方法,但是功能必须在 虚拟机规范 中。

    总结

    ​ 很多时候,初学者不是很容易的区分堆内存、栈内存、方法区、永久代、新生代等等概念。我们可以为jvm的内存做一个总结;方便我们了解和区分这些概念

    • 从归属区分:

      • 归属线程的:虚拟机栈、本地方法栈、pc计数器

      • 归属jvm的:堆、方法区

    • 从功能区分:

      • 保存对象实例数据:堆
      • 保存类的数据:方法区
      • 保存方法变量:虚拟机栈
      • 保存本地方法变量:本地方法栈
      • 保存线程执行位置:pc计数器
  • 相关阅读:
    Apache 浏览器访问限制配置
    Apache 防盗链配置
    Apache 静态缓存配置
    Apache 日志管理
    Apache 域名跳转配置
    搭建完全分布式的hadoop[转]
    Laravel Cheat 表 http://cheats.jesse-obrien.ca/#
    spring-data-mongodb必须了解的操作
    Java MongoDB 资料集合
    MongoDB分片技术[转]
  • 原文地址:https://www.cnblogs.com/dhcao/p/10897256.html
Copyright © 2011-2022 走看看