堆空间算法
Java堆是被全部线程共享的一块内存区域:主要用于存放对象实例,堆是Java 虚拟机所管理的内存中最大的一块缓存
为对象分配内存 = 把一块大小肯定的内存从堆内存中划分出来多线程
堆是垃圾收集器管理的主要区域,所以不少时候也被称作“GC 堆"并发
从堆内存中划分出来须要的内存的方式:操作系统
问题: 内存分配的并发问题,一是能够经过原子性操做来避免,二是能够把内存分配的行为按照线程进行划分,在不一样的空间中进行,每一个线程在Java堆中预先分配一个内存块,称为本地线程分配缓冲(Thread Local Allocation Buffer, TLAB)线程
堆的问题:指针
设置堆的大小对象
堆的大小能够经过-Xms(最小值)和-Xmx(最大值)参数设置,-Xms为JVM启动时申请的最小内存,默认为操做系统物理内存的1/64但小于1G,-Xmx为JVM可申请的最大内存,默认为物理内存的1/4但小于1G内存
如今收集器基本都是采用的分代收集算法,因此Java 堆中还能够细分为:新生代和老年代编译器
新生代:程序新建立的对象都是重新生代分配内存
老年代:用于存放通过屡次新生代GC仍然存活的对象,例如缓存对象,新建的对象也有可能直接进入老年代
栈空间
Java栈是线程私有的,每一个线程对应一个Java栈,每一个线程在执行一个方法时会建立一个对应的栈帧(Stack Frame),栈帧负责存储局部变量变量表、操做数栈、动态连接和方法返回地址等信息。每一个方法的调用过程,至关于栈帧在Java栈的入栈和出栈过程
方法区:方法区用来存储类型的元数据信息
方法区和Java堆同样,是全部线程共享的内存区域,用于存放已被虚拟机加载的类信息、常量、静态变量和即时编译器编译后的代码等数据。 运行时常量池是方法区的一部分,用于存放编译期间生成的各类字面常量和符号引用
程序计数器理解
因为Java 虚拟机的多线程是经过线程轮流切换并分配处理器执行时间的方式来实现的,在任何一个肯定的时刻,一个处理器(对于多核处理器来讲是一个内核)只会执行一条线程中的指令。所以,为了线程切换后能恢复到正确的执行位置,每条线程都须要有一个独立的程序计数器,各条线程之间的计数器互不影响,独立存储,咱们称这类内存区域为“线程私有”的内存。
若是线程正在执行的是一个Java 方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;若是正在执行的是Natvie 方法,这个计数器值则为空(Undefined)。
内存溢出和内存泄漏
内存溢出 out of memory,是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory;好比申请了一个integer,但给它存了long才能存下的数,那就是内存溢出。 内存泄露 memory leak,是指程序在申请内存后,没法释放已申请的内存空间,一次内存泄露危害能够忽略,但内存泄露堆积后果很严重,不管多少内存,早晚会被占光。 memory leak会最终会致使out ofmemory。
例子
new一个对象的过程:A a = new A();
3.在方法区中,存放的都是惟一的整个程序中惟一的元素,例如static变量。