Jdk (Java Development Kit):java语言的软件开发包,包括 Java运行环境Jre。
Jre 样Java Runtime Environment):Java运行环境,包括JVM。
Jvm (Java Virtual Machine):
一种用于计算机设备的规范。
Java语言在不同平台上运行时不需要重新编译。Java语言使用Java虚拟机屏蔽了与具体平台相关的信息,使得Java语言编译程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。
Jdk包括Jre,Jre包括jvm。

属于线程私有内存。占用一块非常小的空间,它的作用可以看作是当前线程所执行的字节码的行号指示器。字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的指令的字节码,分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器来完成。
属于线程私有内存。它的生命周期与线程相同,虚拟机栈描述的是Java方法执行内存模型;每个方法被执行的时候都会同时创建一个栈桢用于存储局部变量表、操作栈、动态链接、方法出口信息等。每一个方法被调用直至执行完成的过程,就对应着一个栈帧再虚拟机中从入栈到出栈的过程。
本地方法栈与虚拟机栈所发挥的作用是非常相似的,只不过虚拟机栈对虚拟机执行Java方法服务,而本地栈是为虚拟机使用到Native方法服务。
是Java虚拟机所管理的内存中最大的一块。Java堆事被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。
是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
是方法区的一部分,Class文件中除了有类的版本、字段、方法、接口等描述信息,还有一项是常量池(Constant PoolTable)用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后存放道方法区的运行时常量池中。
如果线程请求的栈深度大于虚拟机所允许的深度,则抛出StackOverflowError。
Java8取消了永久代,用元空间(Metaspace)代替了,元空间是存在本地内存(Native memory)中。
程序计数器
堆内存存储对象实例。我们只要不断地创建对象。并保证gc roots到对象之间有可达路径来避免垃圾回收机制清除这些对象。就会在对象数量到达最大。堆容量限制后,产生内存溢出异常。
public class Cat {
public static void main(String[] args) {
List list = new ArrayList();
while (true) {
list.add(new Cat());
}
}
}
如果虚拟机在扩展栈时无法申请到足够的内存空间,则抛出StrackOverflowError。
public static void main(String[] args) {
eat();
}
public static void eat () {
eat();
}

堆大小=新生代+老年代。如果是Java8则没有Permanent Generation。
其中新生代(Young)被分为Eden和S0 (from)和S1(to)。
Edem : from : to=8 :1: 1
此比例可以通过-XX:SurvivorRatio来设定。
在GC执行垃圾回收之前,为了区分对象存活与否,当对象被标记为死亡时,GC才回执行垃圾回收,这个过程就是垃圾标记阶段。
比如对象a,只要任何一个对象引用了a,则a的引用计数器就加1,当引用失效时,引用计数器就减1,当计数器为0时,就可以对其回收。
但是无法解决循环引用的问题。
跟搜索算法是以跟为起始点,按照从上到下的方式搜索被根对象集合所连接的目标对象是否可达(使用根搜索算法后,内存中的存活对象都会被根对象集合直接或间接连接着),如果目标对象不可达,就意味着该对象己经死亡,便可以在instanceOopDesc的Mark World中将其标记为垃圾对象。
在根搜索算法中,只有能够被根对象集合直接或者间接连接的对象才是存活对象。
首先标记出所有需要回收的对象,在标记完成后统一回收掉所有的被标记对象。
缺点:

他将可用内存按容量划分为大小相等的两块,每次只使用其中的一块,当这一块内存用完了,就将还存活的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。
优点:
缺点:

先标记出要被回收的对象,然后让所有存活的对象都向一端移动,然后直接清理掉边界以外的内存。解决了复制算法和标记清理算法的问题。

当前商业虚拟机的垃圾收集都采用“分代手机算法”,其实就根据对象存活周期的不同将内存划分为几块,一般是新老年代。根据各个年代的特点采用最适当的收集算法。
进行垃圾收集时,必须暂停其他所有工作线程,Sun将这种事情叫做"Stop The World"。
单线程收集器,单线程的含义在于它会stop the world。垃圾回收时需要stop the world ,直到它收集结束。所以这种收集器体验比较差。
Serial收集器的多线程版本,除了使用采用并行收回的方式回收内存外,其他行为几乎和Serial没区别。
可以通过选项"-XX:+UseParNewGC”手动指定使用ParNew收集器执行内存回收任务。
是一个新生代收集器,也是复制算法的收集器,同时也是多线程并行收集器,与PartNew不同是,它重点关注的是程序达到一个可控制的吞吐量(Thoughput,CPU用于运行用户代码的时间/CPU总消耗时间,即吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间)),高吞吐量可以最高效率地利用CPU时间,尽快地完成程序的运算任务,主要适用于在后台运算而不需要太多交互的任务。
他可以通过2个参数精确的控制吞吐量,更高效的利用cpu。
Parallel Scavenge收集器的老年代版本,使用多线程和标记整理算法。
JDK 1.6中才开始提供。
Concurrent Mar Sweep收集器是一种以获取最短回收停顿时间为目标的收集器。重视服务的响应速度,希望系统停顿时间最短。采用标记-清除的算法来进行垃圾回收。
初始标记仅仅只是标记一下GC Roots能直接关联到的对象,速度很快。
并发标记就是进行Gc Roots Tracing的过程。
重新标记则是为了修正并发标记期间,因用户程序继续运行而导致的标记产生变动的那一部分对象的标记记录,这个阶段停顿时间一般比初始标记时间长,但是远比并发标记时间短。
整个过程中并发标记时间最长,但此时可以和用户线程一起工作。
优点:
缺点:
Garbage First收集器是当前收集器技术发展的最前沿成果。jdk 1.6_update14中提供了g1收集器。
G1收集器是基于标记-整理算法的收集器,它避免了内存碎片的问题。
可以非常精确控制停顿时间,既能让使用者明确指定一个长度为M毫秒的时间片段内,消耗在垃圾收集上的时间不多超过N毫秒,这几乎已经是实时java(rtsj)的垃圾收集器特征了。
极力避免全区域垃圾收集,之前的收集器进行收集的范围都是整个新生代或者老年代。而g1将整个Java堆(包括新生代、老年代)划分为多个大小固定的独立区域,并且跟踪这些区域垃圾堆积程度,维护一个优先级李彪,每次根据允许的收集时间,优先回收垃圾最多的区域。从而获得更高的效率。
加载-》验证-》准备-》解析-》初始化-》使用-》卸载
Java 中,int 类型变量的长度是一个固定值,与平台无关,都是 32 位。意思就是说,在 32 位 和 64 位 的 Java 虚拟机中,int 类型的长度是相同的,都是 32 位或者 4个字节。。
虽然 WeakReference(弱引用) 与 SoftReference(软引用) 都有利于提高 GC 和 内存的效率,但是 WeakReference ,一旦失去最后一个强引用,就会被 GC回收,而软引用虽然不能阻止被回收,但是可以延迟到 JVM 内存不足的时候。
理论上说上 32 位的 JVM 堆内存可以到达 2^32,即 4GB,但实际上会比这个小很多。不同操作系统之间不同,如 Windows 系统大约 1.5GB,Solaris 大约3GB。64 位 JVM 允许指定最大的堆内存,理论上可以达到 2^64,这是一个非常大的数字,实际上你可以指定堆内存大小到 100GB。甚至有的 JVM,如 Azul,堆内存到 1000G 都是可能的。
不能,虽然你可以调用 System.gc() 或者 Runtime.gc(),但是没有办法保证 GC的执行。
在 Java 中最常见的就是强引用, 把一个对象赋给一个引用变量,这个引用变量就是一个强引用。当一个对象被强引用变量引用时,它处于可达状态,它是不可能被垃圾回收机制回收的,即使该对象以后永远都不会被用到 JVM 也不会回收。因此强引用是造成 Java 内存泄漏的主要原因之一。
软引用需要用 SoftReference 类来实现,对于只有软引用的对象来说,当系统内存足够时它不会被回收,当系统内存空间不足时它会被回收。软引用通常用在对内存敏感的程序中。
弱引用需要用 WeakReference 类来实现,它比软引用的生存期更短,对于只有弱引用的对象来说,只要垃圾回收机制一运行,不管 JVM 的内存空间是否足够,总会回收该对象占用的内存。
虚引用需要 PhantomReference 类来实现,它不能单独使用,必须和引用队列联合使用。 虚引用的主要作用是跟踪对象被垃圾回收的状态。
虚拟机设计团队把加载动作放到 JVM 外部实现,以便让应用程序决定如何获取所需的类, JVM 提供了 3 种类加载器:
启动类加载器(Bootstrap ClassLoader)
负责加载 JAVA_HOME\lib 目录中的, 或通过-Xbootclasspath 参数指定路径中的, 且被虚拟机认可(按文件名识别, 如 rt.jar) 的类。
扩展类加载器(Extension ClassLoader)
负责加载 JAVA_HOME\lib\ext 目录中的,或通过 java.ext.dirs 系统变量指定路径中的类库。
应用程序类加载器(Application ClassLoader):
负责加载用户路径(classpath)上的类库。JVM 通过双亲委派模型进行类的加载, 当然我们也可以通过继承 java.lang.ClassLoader实现自定义的类加载器。

当一个类收到了类加载请求,他首先不会尝试自己去加载这个类,而是把这个请求委派给父类去完成,每一个层次类加载器都是如此,因此所有的加载请求都应该传送到启动类加载其中,只有当父类加载器反馈自己无法完成这个请求的时候(在它的加载路径下没有找到所需加载的Class), 子类加载器才会尝试自己去加载。
采用双亲委派的一个好处是比如加载位于 rt.jar 包中的类 java.lang.Object,不管是哪个加载器加载这个类,最终都是委托给顶层的启动类加载器进行加载,这样就保证了使用不同的类加载器最终得到的都是同样一个 Object 对象。

OSGi(Open Service Gateway Initiative),是面向 Java 的动态模型系统,是 Java 动态化模块化系统的一系列规范。
OSGi 服务平台提供在多种网络设备上无需重启的动态改变构造的功能。为了最小化耦合度和促使这些耦合度可管理, OSGi 技术提供一种面向服务的架构,它能使这些组件动态地发现对方。
OSGi 旨在为实现 Java 程序的模块化编程提供基础条件,基于 OSGi 的程序很可能可以实现模块级的热插拔功能,当程序升级更新时,可以只停用、重新安装然后启动程序的其中一部分,这对企业级程序开发来说是非常具有诱惑力的特性。
OSGi 描绘了一个很美好的模块化开发目标,而且定义了实现这个目标的所需要服务与架构,同时也有成熟的框架进行实现支持。但并非所有的应用都适合采用 OSGi 作为基础架构,它在提供强大功能同时,也引入了额外的复杂度,因为它不遵守了类加载的双亲委托模型。
Java对象由三个部分组成:对象头、实例数据、对齐填充。
对象头由两部分组成,第一部分存储对象自身的运行时数据:哈希码、GC分代年龄、锁标识状态、线程持有的锁、偏向线程ID(一般占32/64 bit)。第二部分是指针类型,指向对象的类元数据类型(即对象代表哪个类)。如果是数组对象,则对象头中还有一部分用来记录数组长度。
实例数据用来存储对象真正的有效信息(包括父类继承下来的和自己定义的)。
对齐填充:JVM要求对象起始地址必须是8字节的整数倍(8字节对齐 )。
垃圾回收不会发生在永久代,如果永久代满了或者是超过了临界值,会触发完全垃圾回收(Full GC)。如果你仔细查看垃圾收集器的输出信息,就会发现永久代也是被回收的。这就是为什么正确的永久代大小对避免Full GC是非常重要的原因。请参考下Java8:从永久代到元数据区 (注:Java8中已经移除了永久代,新加了一个叫做元数据区的native内存区)。
结束!!
本以为能够让人眼睛一亮,结果却是令人失望。