加入收藏 | 设为首页 | 会员中心 | 我要投稿 威海站长网 (https://www.0631zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 资源网站 > 空间 > 正文

浅谈虚拟机内存区

发布时间:2019-04-12 03:36:34 所属栏目:空间 来源:Wooola
导读:1. Java 虚拟机内存区概述 我们在编写程序时,经常会遇到OOM(out of Memory)以及内存泄漏等问题。为了避免出现这些问题,我们首先必须对JVM的内存划分有个具体的认识。JVM将内存主要划分为:方法区、虚拟机栈、本地方法栈、堆、程序计数器。 2. Java 虚拟

本例通过不断地建立线程的方式产生内存溢出异常。但是,这样产生的内存溢出异常与栈空间是否足够大并不存在任何联系,或者准确地说,在这种情况下,给每个线程的栈分配的内存越大,反而越容易产生内存溢出异常。 其原因是操作系统分配给每个进程的内存是有限制的,如32位的Windows限制为2GB。。

2.3.4 虚拟机栈的作用

用于存储局部变量、操作栈、动态链接、方法出口

2.3.5 虚拟机栈的运用

对于32位的jvm,默认大小为256kb, 而64位的jvm, 默认大小为512kb,可以通过-Xss设置虚拟机栈的最大值。不过如果设置过大,会影响到可创建的线程数量。

2.3.6 虚拟机栈的使用场景

2.4. 本地方法栈(Native Method Stack)

2.4.1 本地方法栈的概念

本地方法栈与虚拟机栈所发挥的作用很相似,他们的区别在于虚拟机栈为执行Java代码方法服务,而本地方法栈是为Native方法服务。与虚拟机栈一样,本地方法栈也会抛出StackOverflowError和OutOfMemoryError异常。

2.4.2 本地方法栈的特点

  • 线程私有
  • 为Native方法服务

2.4.3 本地方法栈的异常

与虚拟机栈一样,本地方法栈也会抛出StackOverflowError和OutOfMemoryError异常。

2.4.4 本地方法栈的作用

2.4.4.1 与java环境外交互

有时java应用需要与java外面的环境交互。这是本地方法存在的主要原因,你可以想想java需要与一些底层系统如操作系统或某些硬件交换信息时的情况。本地方法正是这样一种交流机制:它为我们提供了一个非常简洁的接口,而且我们无需去了解java应用之外的繁琐的细节。

2.4.4.2 与操作系统交互

JVM支持着java语言本身和运行时库,它是java程序赖以生存的平台,它由一个解释器(解释字节码)和一些连接到本地代码的库组成。然而不管怎样,它毕竟不是一个完整的系统,它经常依赖于一些底层(underneath在下面的)系统的支持。这些底层系统常常是强大的操作系统。通过使用本地方法,我们得以用java实现了jre的与底层系统的交互,甚至JVM的一些部分就是用C写的,还有,如果我们要使用一些java语言本身没有提供封装的操作系统的特性时,我们也需要使用本地方法。

Sun's Java Sun的解释器是用C实现的,这使得它能像一些普通的C一样与外部交互。jre大部分是用java实现的,它也通过一些本地方法与外界交互。例如:类java.lang.Thread

的 setPriority()方法是用java实现的,但是它实现调用的是该类里的本地方法setPriority0()。这个本地方法是用C实现的,并被植入JVM内部,在Windows 95的平台上,这个本地方法最终将调用Win32 SetPriority() API。这是一个本地方法的具体实现由JVM直接提供,更多的情况是本地方法由外部的动态链接库(external dynamic link library)提供,然后被JVM调用。

2.4.5 本地方法栈的运用

2.4.6 本地方法栈的使用场景

  • 与java环境外交互
  • 与操作系统交互

2.5. Java堆(Heap)

2.5.1 Java 堆的概念

Java堆可以说是虚拟机中最大一块内存了。它是所有线程所共享的内存区域,几乎所有的实例对象都是在这块区域中存放。当然,随着JIT编译器的发展,所有对象在堆上分配渐渐变得不那么“绝对”了。

Java堆是垃圾收集器管理的主要区域。由于现在的收集器基本上采用的都是分代收集算法,所有Java堆可以细分为:新生代和老年代。在细致分就是把新生代分为:

  • Eden空间
  • From Survivor
  • To Survivor

根据Java 虚拟机规范的规定:

Java堆可以处于物理上不连续的内存空间中,只要逻辑上是连续的即可,就像我们的磁盘空间一样。在实现时,既可以实现成固定大小的,也可以是可扩展的,不过当前主流的虚拟机都是按照可扩展来实现的。

2.5.2 Java 堆的特点

线程间共享区域,在虚拟机启动时创建

是虚拟机中最大的一块内存,几乎所有的实例对象都是在这块区域中存放

2.5.3 Java 堆的异常

当堆无法再扩展时,会抛出OutOfMemoryError异常。

2.5.4 Java 堆的作用

唯一目的就是存放对象实例,几乎所有的对象实例都在java堆中分配内存

2.5.5 Java 堆的运用

通过 -Xmx 和 -Xms 控制

2.5.6 Java 堆的使用场景

2.6. 程序计算器(Program Counter Register)

2.6.1 程序计算器的概念

类似于PC寄存器,程序计数器是线程私有的区域,每个线程都有自己的程序计算器。可以把它看成是当前线程所执行的字节码的行号指示器。

2.6.2 程序计算器的特点

  • 线程私有
  • 占用的内存空间小
  • 此内存区域是唯一一个在Java虚拟机规范中没有规定任何OOM(OutOfMemoryError)情况的区域

2.6.3 程序计算器的异常

此内存区域是唯一一个在Java虚拟机规范中没有规定任何OOM(OutOfMemoryError)情况的区域

2.6.4 程序计算器的作用

  • 信号指示器:多线程间切换时,需恢复每一个线程的当前执行位置,通过程序计数器中的值寻找要执行的指令的字节码
  • 如果线程在执行Java方法,计数器记录的是正在执行的虚拟机字节码指令地址;如果执行的是Native方法,计数器的值为空(Undefined)。

2.6.5 程序计算器的运用

通过 -Xmx 和 -Xms 控制

2.6.6 程序计算器的使用场景

2.7. 直接内存

2.7.1 直接内存的概念

2.7.1.1 什么是直接内存与非直接内存?

根据官方文档的描述:

A byte buffer is either direct or non-direct. Given a direct byte buffer, the Java virtual machine will make a best effort to perform native I/O operations directly upon it. That is, it will attempt to avoid copying the buffer's content to (or from) an intermediate buffer before (or after) each invocation of one of the underlying operating system's native I/O operations.

byte byffer可以是两种类型,一种是基于直接内存(也就是非堆内存);另一种是非直接内存(也就是堆内存)。

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

对于直接内存来说,JVM将会在IO操作上具有更高的性能,因为它直接作用于本地系统的IO操作。而堆内存如果要作IO操作,会先复制到直接内存,再利用本地IO处理。

从数据流的角度,非直接内存的作用链:

本地IO-->直接内存-->非直接内存-->直接内存-->本地IO

而直接内存的作用链:

本地IO-->直接内存-->本地IO

很明显,在做IO处理时,比如网络发送大量数据时,直接内存会具有更高的效率。

(编辑:威海站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

推荐文章
    热点阅读