面试题答案
一键面试1. 对象创建
- 在Java中,
StringBuilder
通过动态分配内存来存储和操作字符串。每次调用append
等修改字符串的方法时,如果当前容量不足,StringBuilder
会创建一个新的更大的字符数组,并将原数组内容复制到新数组中。例如:
StringBuilder sb = new StringBuilder();
sb.append("Hello");
sb.append(" World");
- 上述代码中,随着
append
操作的进行,可能会多次创建新的字符数组对象用于存储扩展后的字符串内容。
2. 存活周期
StringBuilder
对象本身在其作用域内一直存活,直到其引用不再可达。比如在一个方法内部定义的StringBuilder
,当方法执行完毕,且没有外部对该StringBuilder
对象的引用时,它就符合垃圾回收的条件。- 对于
StringBuilder
内部的字符数组,其存活周期与StringBuilder
对象紧密相关。只要StringBuilder
对象存活,字符数组也存活,因为StringBuilder
持有对字符数组的引用。
3. 对堆内存使用的影响
- 频繁的字符串操作会导致
StringBuilder
不断扩展内部字符数组,从而占用更多的堆内存。例如,如果初始容量为16,不断append
字符串内容,当超过16个字符时,就会扩容,可能扩为原来的2倍加2(不同版本实现可能略有差异)。这会导致堆内存中连续的内存块被占用,且可能造成内存碎片。 - 当
StringBuilder
对象不再被引用,但其占用的内存并不会立即释放,只有在垃圾回收机制运行时才会回收这部分内存。
4. 垃圾回收算法处理相关对象
- 标记 - 清除算法:如果Java使用标记 - 清除算法,当
StringBuilder
对象及其内部字符数组不再被任何引用指向时,垃圾回收器会首先标记这些对象,然后在堆内存中清除这些标记的对象,释放其所占用的内存空间。但此算法可能产生内存碎片。 - 标记 - 整理算法:对于
StringBuilder
相关对象,标记 - 整理算法同样先标记不再被引用的对象,然后将存活的对象向一端移动,最后清除边界以外的内存,这样可以减少内存碎片,使得堆内存空间更加紧凑。 - 复制算法:如果堆内存采用复制算法,在垃圾回收时,会将
StringBuilder
对象及其他存活对象复制到另一块内存空间,然后清除原空间。这种算法适用于对象存活率较低的区域,能高效回收内存,但需要额外的空间。 - 分代收集算法:Java堆内存一般分为新生代和老年代。
StringBuilder
对象在创建初期通常在新生代,如果在新生代经历多次垃圾回收后仍然存活,会被晋升到老年代。在新生代采用复制算法进行垃圾回收,老年代则采用标记 - 清除或标记 - 整理算法。例如,频繁创建和销毁的小StringBuilder
对象可能在新生代就被回收,而长期存活的StringBuilder
对象会进入老年代,老年代垃圾回收频率相对较低。