• JVM调优之StringTable调优


    jdk1.8之后,JVM内存结构如下

     所谓的StringTable,即字符串常量池(以下简称串池),存放在堆内存中。

     我们先介绍一下intern方法

    1. String s = "ab";
    2. //将这个字符串对象尝试放入串池,如果有则并不会放入,如果没有则放入串池,会把串池中的对象返回
    3. String s2 = s.intern();

    调优方法1.因为StringTable是由HashTable实现的,所以可以适当增加HashTable桶的个数,来减少字符串放入串池所需要的时间。

    示例代码:遍历文本文件,读取每一行的内容放入串池

    1. public class Demo1_24 {
    2. public static void main(String[] args) throws IOException {
    3. try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream("linux.words"), "utf-8"))) {
    4. String line = null;
    5. long start = System.nanoTime();
    6. while (true) {
    7. line = reader.readLine();
    8. if (line == null) {
    9. break;
    10. }
    11. line.intern();
    12. }
    13. System.out.println("cost:" + (System.nanoTime() - start) / 1000000);
    14. }
    15. }
    16. }

    linux.words是存放文本的文件(实际文本有四百多万行,只粘贴部分做示例)

    1. 1080
    2. 10-point
    3. 10th
    4. 11-point
    5. 12-point
    6. 16-point
    7. 18-point
    8. 1st
    9. 2
    10. 20-point
    11. 2,4,5-t
    12. 2,4-d
    13. 2D
    14. 2nd
    15. 30-30
    16. 3-D
    17. 3-d
    18. 3D
    19. 3M
    20. 3rd
    21. 48-point
    22. 4-D
    23. 4GL
    24. 4H
    25. 4th
    26. 5-point
    27. 5-T
    28. 5th
    29. 6-point
    30. 6th
    31. 7-point
    32. 7th
    33. 8-point
    34. 8th
    35. 9-point
    36. 9th
    37. -a
    38. A
    39. A.
    40. a
    41. a'
    42. a-
    43. a.
    44. A-1
    45. A1
    46. a1
    47. A4
    48. A5
    49. AA
    50. aa

    我们运行程序,发现耗时不到1s

     然后我们设置JVM运行参数,修改桶的数量为1009,再次运行

    -XX:+PrintStringTableStatistics -XX:StringTableSize=1009

     

     运行结果耗时8秒 如下图

     StringTable默认的桶的数量是60013,当桶的数量设置变小,哈希碰撞的概率增加,链表长度

     变长,数据插入就会变慢,可以适当增加HashTable桶的个数,来减少字符串放入串池所需要的时间。

    调优方法2:如果应用里有大量的字符串,而且字符串可能存在重复的问题,可以通过intern方法让字符串入池,减少字符串个数(触发垃圾回收 没入池的字符串被回收掉),节约堆内存的使用

    示例代码:同样是遍历上述的文本文件,将每一行的内容放入ArrayList中,循环操作10次

    1. public class Demo1_25 {
    2. public static void main(String[] args) throws IOException {
    3. List<String> address = new ArrayList<>();
    4. System.in.read();
    5. for (int i = 0; i < 10; i++) {
    6. try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream("linux.words"), "utf-8"))) {
    7. String line = null;
    8. long start = System.nanoTime();
    9. while (true) {
    10. line = reader.readLine();
    11. if(line == null) {
    12. break;
    13. }
    14. address.add(line);
    15. }
    16. System.out.println("cost:" +(System.nanoTime()-start)/1000000);
    17. }
    18. }
    19. System.in.read();
    20. }
    21. }

    运行以上代码,我们控制台输入

    jvisualvm 

    查看字符串所占用的内存使用情况 

    然后我们敲下Enter执行我们的主程序,遍历文本文件,发现内存占用飙高很多

     

     然后我们修改代码(只改了一行代码,address.add(line.intern())

    1. public class Demo1_25 {
    2. public static void main(String[] args) throws IOException {
    3. List<String> address = new ArrayList<>();
    4. System.in.read();
    5. for (int i = 0; i < 10; i++) {
    6. try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream("linux.words"), "utf-8"))) {
    7. String line = null;
    8. long start = System.nanoTime();
    9. while (true) {
    10. line = reader.readLine();
    11. if(line == null) {
    12. break;
    13. }
    14. //仅修改这一处代码
    15. address.add(line.intern());
    16. }
    17. System.out.println("cost:" +(System.nanoTime()-start)/1000000);
    18. }
    19. }
    20. System.in.read();
    21. }
    22. }

     再运行查看内存占用情况,下降了很多

     我们循环遍历10次,会在堆中产生很多重复的字符串,而ArrayList中存放的对象都来自串池,堆中的字符串 如果没被引用,会被垃圾回收掉,从而节约了堆内存的使用

  • 相关阅读:
    Python入门必备基础
    vulnhub靶机Presidential
    【OS】操作系统课程笔记 第五章 并发性——互斥、同步和通信
    JS高级:对象创建模式
    代码随想录算法训练营第五十八天丨 动态规划part18
    http和https区别,第三方证书如何保证服务器可信
    【深度学习】多任务学习 多个数据集 数据集漏标
    电子拼图思维逻辑机的破解思路
    InternImage
    关于SQL优化
  • 原文地址:https://blog.csdn.net/jack__love/article/details/128156486