JVM(一):内存区域和类的加载

0.JVM和字节码

  • JVM实际上现在已经成为了跨语言平台,只要按字节码生成规则,都可以在JVM上运行
  • JVM规范中最具含金量的虚拟机实现是HotSpot也是JDK1.3至今的默认虚拟机,其他的还有JRockit、IBM J9等
  • JDK9之后 G1垃圾回收器完全替代了CMS
  • 编译成规范的字节码的好处是:一次编译,到处运行

0.1JVM和传统虚拟机

  • 传统意义上的虚拟机如VMware,它是在硬件层面模拟了一个操作系统
  • 而JVM是在操作系统之上,解释运行字节码文件的一个细粒度的虚拟机。它没有和硬件直接交互
  • 他们的层次是: 硬件——操作系统——JVM——字节码

0.2三种虚拟机

引用

引用

引用

1.内存管理概述

  • 对于Java程序员来说,在JVM自动内存管理机制的帮助下,不需要为每一个new出来的对象配对delete/free去释放内存,不容易出现出现内存泄漏和内存溢出问题。
    但是一旦出现了这方面的问题,不了解JVM是怎么使用内存的话就很难排查错误。
  • HotSpot是JVM概念的一个实现,最初由Sun开发,现在由Oracle拥有。 还有其他JVM规范的实现,如JRockit , IBM J9等等。

2.运行时数据区

JVM运行时会把它所管理的内存划分为若干个不同的数据区,有的区域随JVM启动而一直存在,有的区域依赖用户线程的启动和结束。它包括了以下几种运行时数据区。
(按相关性和逻辑顺序依次介绍)

2.1程序计数器

首先:JVM的多线程是靠线程轮流切换、分配处理器执行时间来实现的,那么在切换的过程中,如何确定当前线程执行到哪里了呢?

  • 线程私有:每个线程都有自己独立的程序计数器,独立存储,互不影响
  • 程序计数器占用的内存空间很小
  • 字节码解释器就是通过改变程序计数器的值,来选取下一条需要执行的字节码指令
  • 分支、循环、跳转、异常处理、线程恢复等功能都依赖于程序计数器

2.2虚拟机栈

2.2.1概念

  • 线程私有,其生命周期和线程相同
  • 每一个方法被执行的时候,JVM都会同步创建一个栈帧
  • 栈帧用于存储:局部变量、操作数栈、动态连接、方法出口等信息
  • 每一个方法从调用到结束,对应一个栈帧的入栈出栈

2.2.2局部变量表

虚拟机栈一般都用来指局部变量表,一般包括:

  • 8种基本数据类型(其中long和double占用两个局部变量槽Slot
  • 对象引用,如People p = new People()种的p;int[] arr = new int[]{}中的arr
  • 因此虚拟机栈的大小是可以完全确定的,如果线程请求的虚拟机栈深度>JVM允许的最大深度,则会报错StackOverflowError即俗称的爆栈,在递归调用的时候较为容易出现爆栈的情况

2.3本地方法栈

  • 线程私有
  • 本地:native:即指编写JDK所用到底层C++库
  • 它和虚拟机栈大同小异,区别就是:虚拟机栈调用的是Java方法的字节码,本地方法栈调用的是C++的库
  • JVM的HotSpot实现将它们二者合二为一了

2.4堆

一般Java程序员在没有了解JVM的情况下,喜欢把JVM粗略的分为堆和栈,这种分法来自于C++,但JVM规范中的划分更加复杂

  • 多线程共享
  • 堆是JVM管理内存中最大的一块,几乎所有的对象实例都存放于此
  • 对于大的对象(典型如数组)一般都是使用连续的内存空间
  • Java堆是可扩展的,一般通过设置-Xmx和-Xms,超过最大限度后报错OutOfMemoryError,即俗称的OOM
  • Java堆也叫GC堆,因为其是垃圾收集器管理内存的区域

2.5方法区和元空间

在JDK8以前,很多程序员喜欢使用HotSpot来开发Java程序,HotSpot将分代设计拓展至了方法区,因此很多人将方法区和永久代混为一谈。此外永久代也出现了很多严重的内存泄露BUG,因此目前被摒弃

对于JRockit、IBM J9虚拟机来说,永久代被完全摒弃,取而代之的是元空间,同理方法区是HotSpot独有的

  • 多线程共享
  • 准确来说,永久代实现了方法区,在JDK8之后替换为了元空间实现方法区。二者效果相近。
  • 对于以前永久代中的静态变量、字符串常量池,目前是放在了堆Heap中
  • 元空间使用本地内存也就意味着只要本地内存足够,就不会出现OOM的错误。
  • Java1.8的运行时数据区域如图所示。方法区已经不见了踪影,多出来的是叫做元数据区的区域。
    引用

2.6运行时常量池

Class常量池(又称常量池) :主要用于存放两大类常量:字面量(Literal)和符号引用量(Symbolic References)。

字面量相当于Java语言层面常量的概念,如文本字符串,声明为final的常量值等;

符号引用则属于编译原理方面的概念,包括了三种类型的常量:类和接口的全限定名字段名称和描述符方法名称和描述符

引用

2.7*直接内存

这个直接内存并不是JVM运行时数据区的一部分,它是JDK4引入的NIO的一种缓冲优化策略:
可以将Native库直接分配到堆外内存,然后通过Java堆中的一个缓冲对象来引用,避免了反复在Java堆和Native堆的复制数据。

3.类的加载

3.1

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值