做平面设计什么素材网站好使,网站建设 作用,青海省建设局网站,廊坊做网站的企业哪家好文章目录 对象引用强引用软引用#xff08;SoftReference#xff09;弱引用#xff08;WeakReference#xff09;考一考 虚引用#xff08;PhantomReference#xff09;总结 垃圾回收新生代老年代永生代 内存管理小技巧尽量使用直接量使用StringBuilder和StringBuffer进行… 文章目录 对象引用强引用软引用SoftReference弱引用WeakReference考一考 虚引用PhantomReference总结 垃圾回收新生代老年代永生代 内存管理小技巧尽量使用直接量使用StringBuilder和StringBuffer进行字符串拼接尽早释放无用对象的引用尽量少用静态变量避免在循环中创建对象缓存经常使用的对象避免使用finalize()方法使用SoftReference 注本文是对《疯狂Java面试讲义》的小结。 对象引用
Java通过 new 关键字来创建对象实例JVM会在堆内存中为对象分配空间。当对象失去引用时JVM的垃圾回收机制会自动清理对象回收内存空间。
可以把对象的引用关系理解为有向图。如果某个对象在图中处于不可达状态则认为该对象不再被引用。
Java的对象引用方式有
强引用软引用弱引用虚引用
下面举例说明各种引用方式。
准备已知类 Person 定义如下
public class Person {private String name;private int age;......
}强引用
强引用是最普通、最常见的引用方式。 Person person new Person(Tom, 20);强引用的对象一定不会被JVM回收。
对于强引用当内存占用过多时就会出现 OutOfMemoryError 。 Person[] arr1 new Person[80000];for (int i 0; i arr1.length; i) {arr1[i] new Person(Tom i, i % 20);System.out.println(arr1[i]);}正常情况下运行结果OK。为了模拟内存被占满的情况我们把JVM的内存设置为较低值
-Xmx8m -Xms8m如果是在命令行下运行
java -Xmx8m -Xms8m xxxxxx如果是IntelliJ IDEA右键More Run/Debug - Modify Run Configuration… 在弹出的对话框里点击“Modify options”在子菜单中确保勾选了“Add VM options”然后填入 -Xmx8m -Xms8m 运行结果如下
......
Person{nameTom61694, age14}
Person{nameTom61695, age15}
Exception in thread main java.lang.OutOfMemoryError: Java heap spaceat java.base/jdk.internal.misc.Unsafe.allocateUninitializedArray(Unsafe.java:1375)at java.base/java.lang.StringConcatHelper.newArray(StringConcatHelper.java:494)
......可见在创建到大约60000个对象的时候内存就会溢出。
软引用SoftReference
软引用的作用是当内存空间充足时它不会被系统回收但是当内存空间不足时它就会被系统回收。
软引用的用法如下 SoftReferencePerson person new SoftReference(new Person(Tom, 20));......person.get();把上面强引用的代码稍作修改如下 SoftReferencePerson[] arr1 new SoftReference[80000];for (int i 0; i arr1.length; i) {arr1[i] new SoftReference(new Person(Tom i, i % 20));System.out.println(arr1[i].get());}System.out.println(arr1[1].get());System.out.println(arr1[3].get());System.out.println(arr1[79999].get());运行结果如下别忘了设置JVM内存
......
Person{nameTom79998, age18}
Person{nameTom79999, age19}
null
null
Person{nameTom79999, age19}可见80000个对象依次创建成功内存没有溢出但是创建完毕后再访问这些对象时发现前面一部分对象已经变成null了。这是由于在创建后面的对象时内存不够触发了垃圾回收前面的软引用对象被清除了。
多次运行代码最后一行有时也会打印出 null 这说明每次垃圾回收的时机和回收的对象数量是不一定的。
弱引用WeakReference
弱引用和软引用类似区别在于不管内存是否充足只要有垃圾回收弱引用对象就会被回收。
弱引用的用法如下 WeakReferencePerson person new WeakReference(new Person(Tom, 20));System.out.println(person.get());System.gc();System.runFinalization();System.out.println(person.get());运行结果如下无需设置JVM内存
Person{nameTom, age20}
null可见垃圾回收时弱引用对象被回收了。
与 WeakReference 功能类似的还有 WeakHashMap 。
对于map里的key值如果其对象是弱引用则在垃圾回收时会把该对象回收并把该key值从map里移除。 WeakHashMapPerson, String map new WeakHashMap();map.put(new Person(Tom, 20), aaa);map.put(new Person(Jerry, 30), bbb);System.out.println(map);System.gc();System.runFinalization();System.out.println(map);运行结果如下
{Person{nameJerry, age30}bbb, Person{nameTom, age20}aaa}
{}考一考
下面的代码运行结果是什么 WeakHashMapPerson, String map new WeakHashMap();Person person1 new Person(Tom, 20);map.put(person1, aaa);// person1 null;Person person2 new Person(Jerry, 30);map.put(person2, bbb);// person2 null;System.out.println(map);System.gc();System.runFinalization();System.out.println(map);乍一看似乎跟前一个例子没什么太大区别但运行结果是不同的
{Person{nameJerry, age30}bbb, Person{nameTom, age20}aaa}
{Person{nameJerry, age30}bbb, Person{nameTom, age20}aaa}这两个key对象为什么没有被回收掉呢其实原因很简单因为person1和person2还在引用它们。这是强引用所以不会被垃圾回收。要想被垃圾回收只需解除强引用参见被注释掉的那两行代码。
虚引用PhantomReference
虚引用的主要作用是跟踪对象被垃圾回收的状态。
虚引用不能单独使用必须和引用队列ReferenceQueue一起使用。引用队列保存了被回收后对象的引用。它和软引用、弱引用等联合使用这些对象被回收时会把引用添加到相关联的引用队列中。 ReferenceQueuePerson queue new ReferenceQueue();PhantomReferencePerson phantomReference new PhantomReference(new Person(Tom, 20), queue);// 虚引用的 get() 方法总是返回nullSystem.out.println(phantomReference.get());// 还没做垃圾回收所以队列为空System.out.println(queue.poll());System.gc();System.runFinalization();// 垃圾回收后虚引用对象在队列中System.out.println(queue.poll());运行结果如下
null
null
java.lang.ref.PhantomReference36baf30c既然虚引用都get不到实际对象那它到底有什么用呢
看起来虚引用的用处就是会触发一个事件。我们可以另起一个线程对队列进行监听比如
remove() 阻塞方法poll() 非阻塞方法
这样当对象被回收时我们就会得到通知做相应的处理比如清理资源。
总结
强引用软引用弱引用垃圾回收时不会被回收YNN垃圾回收时若内存不足就会被回收NYY只要有垃圾回收就会被回收NNY
垃圾回收
垃圾回收机制主要做两件事
跟踪每个Java对象的可达状态回收不可达对象的内存清理分配和回收过程中产生的内存碎片
垃圾回收的设计思想
串行和并行使用单CPU还是多CPU来做回收并发和停止stop-the-world回收时应用是否暂停紧凑和不紧凑如果只是回收对象则内存可能会产生很多碎片。把所有活着的对象复制到一起可以避免内存碎片
回收方式
复制把内存分成两个相同的空间A和B以A空间为例从根开始把每个可达对象复制到B空间最后把整个A空间重置标记清除mark-sweep从根开始标记每个可达对象最后回收所有没有标记可达的对象标记清除紧凑mark-sweep-compact从根开始标记每个可达对象最后把所有活着的对象搬迁在一起并回收其它内存空间
分代内存
新生代Young大部分对象存活时间不会很长处于新生代老年代Old少量对象存活时间很长处于老年代永生代Permanent主要用于存放Class对象方法等信息
新生代
新生代又分为Eden伊甸园区和Survivor区。
绝大部分对象先分配到Eden区而Survivor区的对象至少熬过一次垃圾回收。
Survivor区又分为From区和To区参见上面提到的“复制”回收方式。
垃圾回收时将Eden区和From区的可达对象复制到To区然后清空Eden区和From区最后把From和To互换一下。
老年代
如果一个对象熬过了数次垃圾回收就可能会被转入老年代。
老年代的垃圾回收频率无需太高因为老年代的对象都很能熬。
次要回收新生代的垃圾回收频率较高主要回收新生代和老年代的垃圾回收频率较低
老年代的垃圾回收通常采用标记清除紧凑算法。
永生代
主要用于存放Class对象方法等信息默认为64MB。
内存管理小技巧
尽量使用直接量 String str1 hello; // 在字符串缓存池里缓存了hello字符串String str2 new String(hello); //同上此外还多创建了一个char[]数组使用StringBuilder和StringBuffer进行字符串拼接
String字符串是不可变的如果直接对字符串拼接将产生大量的临时字符串。 String str1 hello;String str2 world;String str3 !!!;String result1 str1 str2 str3; // 产生大量的临时字符串System.out.println(result1);StringBuilder result2 new StringBuilder();result2.append(str1);result2.append(str2);result2.append(str3);System.out.println(result2.toString());StringBuffer result3 new StringBuffer();result3.append(str1);result3.append(str2);result3.append(str3);System.out.println(result3.toString());尽早释放无用对象的引用 Person person new Person(Tom, 20);person.doSomething();// person null;......本例中创建并使用完person对象后最好将其释放参见注释处代码否则person变量在其作用域范围内会一直持有对象引用导致对象无法被系统回收。
尽量少用静态变量
class A {static B b new B();
}本例中b是A类的静态变量其生命周期与A类一致存入永生代。
避免在循环中创建对象 for (int i 0; i 100; i) {Person person new Person(Tom, 20);......}创建了100个Person对象它们的生存时间都很短。系统需要不断的分配和回收内存。
缓存经常使用的对象
典型的例子是数据库连接池。
避免使用finalize()方法
垃圾回收的工作量已经很大了尤其是新生代对象很多回收频繁若再使用finalize()方法清理资源更加重了垃圾回收的负担。
使用SoftReference
参见前面的介绍。
注意SoftReference和WeakReference的不确定性在使用对象时应检查其是否为空。