1)happens before: 一个线程前一个操作对后一个操作可见,具有传递性。确保多线程执行程序结果不变。
2)as if serial: 无论怎么重排序,程序执行结果不变,即不能对数据依赖的操作重排序。确保单线程执行程序结果
新生代内存不够用时候发生 MGC 也叫 YGC, JVM 内存不够的时候发生 FGC
除直接调用System.gc外,触发Full GC执行的情况有如下四种。
1)java 内存分配与回收策略
1. 对象优先在堆的 Eden 区分配
2. 大对象直接进入老年代
3. 长期存活的对象将直接进入老年代
2)Minor GC 和 Major GC
当 Eden 区没有足够的空间进行分配时,虚拟机会执行一次 Minor GC。Minor Gc 通常发生在新生代的 Eden 区,在这个区的对象生存期短,往往发生 Gc 的频率较高,回收速度比较快;Full Gc/Major GC 发生在老年代,一般情况下,触发老年代 GC的时候不会触发 Minor GC,但是通过配置,可以在 Full GC 之前进行一次 MinorGC 这样可以加快老年代的回收速度。
Minor GC、Young GC、Full GC、Old GC、Major GC、Mixed GC傻傻分不清_背井的博客-CSDN博客_minorgc和younggc
垃圾回收不会发生在永久代,如果永久代满了或者是超过了临界值,会触发完全垃圾回收(Full GC)。如果你仔细查看垃圾收集器的输出信息,就会发现永久代也是被回收的。这就是为什么正确
的永久代大小对避免Full GC是非常重要的原因。请参考下Java8:从永久代到元数据区 (注:Java8中已经移除了永久代,新加了一个叫做元数据区的native内存区)
为了避免OOM异常。因为通常使用PermSize和MaxPermSize设置永久代的大小就决定了永久代的上限,但是不是总能知道应该设置为多大合适, 如果使用默认值很容易遇到OOM错误。当使用元空间时,可以加载多少类的元数据就不再由MaxPermSize控制, 而由系统的实际可用空间来控制啦。
不能,虽然你可以调用 System.gc() 或者 Runtime.gc(),但是没有办法保证 GC的执行。
GC 的时候必须要等到 Java 线程都进入到 safepoint 的时候 VMThread 才能开始执行 GC,
1) 循环的末尾 (防止大循环的时候一直不进入 safepoint,而其他线程在等待它进入
safepoint)
2) 方法返回前
3) 调用方法的 call 之后
4) 抛出异常的位置
可以通过 java.lang.Runtime 类中与内存相关方法来获取剩余的内存,总内存及最大堆内存。通过这些方法你也可以获取到堆使用的百分比及堆内存的剩余空间。Runtime.freeMemory() 方法返回剩余空间的字节数,Runtime.totalMemory()方法总内存的字节数,Runtime.maxMemory() 返回最大内存的字节数。
内存泄漏是指不再被使用的对象或者变量一直被占据在内存中。理论上来说, Java是有GC垃圾回收机制的,也就是说,不再被使用的对象,会被GC自动回收 掉,自动从内存中清除。但是,即使这样,Java也还是存在着内存泄漏的情况,java导致内存泄露的原因 很明确:长生命周期的对象持有短生命周期对象的引用就很可能发生内存泄露, 尽管短生命周期对象已经不再需要,但是因为长生命周期对象持有它的引用而导 致不能被回收,这就是java中内存泄露的发生场景。
原因:
让我们用下面的例子来看看为什么会发生内存泄露。如下图所示,对象A引用对象B,A的生命周期(t1-t4)比B的生命周期(t2-t3)要长,当B在程序中不再被使用的时候,A仍然引用着B。在这种情况下,垃圾回收器是不会回收B对象的,这就可能造成了内存不足问题,因为A可能不止引用着B对象,还可能引用其它生命周期比A短的对象,这就造成了大量无用对象不能被回收,且占据了昂贵的内存资源。同样的,B对象也可能引用着一大堆对象,这些被B对象引用着的对象也不能被垃圾回收器回收,所有的这些无用对象消耗了大量内存资源。
怎样阻止内存泄露:
内存溢出 out of memory,是指程序在申请内存时,没有足够的内存空间供其使用,出现out of
memory;比如申请了一个integer,但给它存了long才能存下的数,那就是内存溢出。
内存泄露 memory leak,是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。
memory leak 会最终会导致 out of memory
内存溢出就是你要求分配的内存超出了系统能给你的,系统不能满足需求,于是产生溢出。内存泄漏是指你向系统申请分配内存进行使用(new),可是使用完了以后却不归还(delete),结果你申请到的那块内存你自己也不能再访问(也许你把它的地址给弄丢了),而系统也不能再次将它分配给需要的程序。一个盘子用尽各种方法只能装4个果子,你装了5个,结果掉倒地上不能吃了。这就是溢出!比方说栈,栈满时再做进栈必定产生空间溢出,叫上溢,栈空时再做退栈也产生空间溢出,称为下溢。就是分配的内存不足以放下数据项序列,称为内存溢出。
Java内存模型与硬件内存架构之间存在差异。硬件内存架构没有区分线程栈和堆。对于硬件,所有的线程栈和堆都分布在主内存中。部分线程栈和堆可能有时候会出现在CPU缓存中和CPU内部的寄存器中。如下图所示:
24. JDK自带的定位问题的工具?
jps –l # 输出输出完全的包名,应用主类名,jar的完全路径名
- # 基本
- jstack 2815
- jstack -m 2815 # java和native c/c++框架的所有栈信息
- jstack -l 2815 # 额外的锁信息列表,查看是否死锁
jinfo 2815 # 输出当前 jvm 进程的全部参数和系统属性
jstat -gcutil 2815 1000