那么问题来了,懂了 内存区域 之后,你能干嘛?
就 Android 开发来说,如果不知道虚拟机是怎么样使用内存的,一旦发生内存泄漏和溢出方面的问题,那么排查起来就比较困难了,而且之所以程序在正常情况下不会发生溢出和泄漏的情况就是在虚拟机自动内存管理机制的帮助下完成的。
内存区域划分
可以知道 运行时数据区 划分有 线程共享 和 线程私有
线程共享:
方法区、Java堆
线程私有:
堆虚拟机栈、本地方法栈、程序计数器
Java 堆(Java Heap):
特点:
是 Java 虚拟机管理内存中最大的一块,是线程共享的内存区域,垃圾收集器管理的主要区域,因此又称为“GC 堆”(Garbage Collectioned Heap)
作用:
主要是存放对象的实例
抛出的异常:
- 当对象数量到达最大堆的容量限制后就会产生内存溢出异常
- 当出现Java堆内存溢出时,异常堆栈信息“java.lang.OutOfMemoryError”会跟着进一步提示“Java heap space”。
方法区:
特点:
是线程共享的内存区域
作用
存储已被虚拟机加载的信息、常量、静态变量、类信息、JIT编译后的代码等数据
抛出的异常
- 如果产生大量的类或者大量的字符串常量(运行时常量池溢出)可能导致方法区溢出
- 通常伴随 java.OutOfMemory Error:PermGen space
虚拟机栈
特点:
是线程私有的内存区域
作用
是Java方法执行的内存模型,描述一个方法从调用到完成的过程,方法执行时创建栈帧,用于存储局部变量表,操作数栈、动态链接,方法出入口等信息。
抛出的异常
java.lang.StackOverflow Error 、java.lang.OutOfMemoryError
本地方法栈
特点:
是线程私有的内存区域
作用
为 Native 提供服务
抛出的异常
java.lang.StackOverflow Error 、java.lang.OutOfMemoryError
程序计数器
特点:
是线程私有的内存区域
作用
是当前线程所执行的字节码的行号指示器。
如果线程正在执行的是一个Java方法,那么计数器记录的是正在执行的虚拟机字节码指令的地址;
如果线程正在执行的是一个Native方法,那么计数器的值则为空。
在Java虚拟机规范中,是唯一一个没有规定任何OutOfMemoryError情况的区域。
本地内存(Direct Memory)
直接内存并不是虚拟机运行时数据区的一部分,也不是Java 虚拟机规范中农定义的内存区域。在JDK1.4 中新加入了 NIO(New Input/Output) 类,引入了一种基于通道(Channel)与缓冲区(Buffer)的I/O 方式,它可以使用 native 函数库直接分配堆外内存,然后通脱一个存储在Java堆中的 DirectByteBuffer 对象作为这块内存的引用进行操作。这样能在一些场景中显著提高性能,因为避免了在Java堆和Native堆中来回复制数据。