关于一个GC回收内存总量的疑问

本文探讨了使用多种方法进行文件写入操作,并通过分析GC日志,揭示了不同写入策略对垃圾回收的影响。重点介绍了如何优化内存管理和减少GC频率,以提升应用程序性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

package ringBuffer;

import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;

public class PerformanceWriteTest {
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		String outputFile = "F:\\test\\ioTest.txt";
		Long length = 0L ; 
		Long totalTime = 0L;
		
//        try {
//   	   		raf = new RandomAccessFile("F:\\test\\ioTest.txt", "rw");
//   	   		FileChannel fc = raf.getChannel();
//   	   		mbb = fc.map(MapMode.READ_WRITE, 0, 85*1024*1024);
//		} catch (FileNotFoundException e) {
//			e.printStackTrace();
//		} catch (IOException e) {
//			e.printStackTrace();
//		}
		
		for (int j = 0; j < 5; j++) {
				StringBuffer sb = new StringBuffer();
				for (Integer i = 0; i < 1000000; i++) {
					sb.append(j+i.toString() + "V");
				}
				sb.append("S");
				length = (long) sb.toString().length() ;
			    long start =  System.currentTimeMillis() ;
				appendFileTest(outputFile,sb.toString());
				totalTime = totalTime + (System.currentTimeMillis() - start) ;
		}
		System.out.println(" Total Data is : " + length*5/1000 + " Kbytes! ") ;
		System.out.println(" Total Time is : " + totalTime) ;
		System.out.println(" Averge Speed is :" + length*5/(totalTime*1000) + " Kbytes");
	}

	private static void appendFileTest(String outputFile, String msgs) {
//             append1(outputFile, msgs) ;  //FileOutputStream
//             append2(outputFile, msgs) ;  //FileWriter
             append3(outputFile, msgs) ;  //RandomAccessFile 
//			   append4(outputFile, msgs) ;  //RandomAccessFile 
	}

	private static void append1(String outputFile, String msgs) {
		BufferedWriter out = null;   
	    try {   
	         out = new BufferedWriter(new OutputStreamWriter(   
	                  new FileOutputStream(outputFile, true)));   
	         out.append(msgs) ;
	        } catch (Exception e) {   
	            e.printStackTrace();   
	        } finally {   
	            try {   
	                out.close();   
	            } catch (IOException e) {   
	                e.printStackTrace();   
	            }   
	        }   
	}

	private static void append2(String outputFile, String msgs) {
		try {   
            FileWriter writer = new FileWriter(outputFile, true);     // 打开一个写文件器,构造函数中的第二个参数true表示以追加形式写文件   
            writer.write(msgs);   
            writer.close();   
        } catch (IOException e) {   
            e.printStackTrace();   
        }   
	}

	private static void append3(String outputFile, String msgs) {
		  try {   
	            RandomAccessFile randomFile = new RandomAccessFile(outputFile, "rw");    // 打开一个随机访问文件流,按读写方式   
	            long fileLength = randomFile.length();    // 文件长度,字节数   
	            randomFile.seek(fileLength);    // 将写文件指针移到文件尾
	            randomFile.writeBytes(msgs);   
	            randomFile.close();   
	        } catch (IOException e) {   
	            e.printStackTrace();   
	        }   
	}
	
	private static void append4(String outputFile, String msgs) {
		  try {   
			    mbb.position(pos) ;
			    mbb.put(msgs.getBytes());
			    pos = pos + msgs.getBytes().length ;
			    raf.close();   
	        } catch (IOException e) {   
	            e.printStackTrace();   
	        }   
	}

	static RandomAccessFile raf ;
	static MappedByteBuffer mbb  ;
	static Integer pos = 0 ;
}


加入-XX::+PrintGC, 打印的结果是:

[GC 32704K->2928K(124992K), 0.0024320 secs]
[GC 35632K->5200K(124992K), 0.0020096 secs]
[GC 29268K->5200K(124992K), 0.0014802 secs]
[GC 37904K->9792K(157696K), 0.0035590 secs]
[GC 60504K->9840K(157696K), 0.0008594 secs]
[GC 75248K->28224K(224640K), 0.0079131 secs]
[GC 159040K->30572K(224768K), 0.0014706 secs]
[GC 159705K->37516K(355008K), 0.0029869 secs]
[GC 299148K->46668K(355008K), 0.0031385 secs]
[GC 308300K->48980K(511296K), 0.0010842 secs]
[GC 467604K->55860K(511616K), 0.0036752 secs]


可以看到一共产生了11次GC,  而让我困惑的是,使用jstat -gcutil 18360 20 200 > 2.txt

结果如下:

  S0     S1     E      O      P     YGC     YGCT    FGC    FGCT     GCT   
  0.00   0.00  12.01   0.00  11.93      0    0.000     0    0.000    0.000
  0.00   0.00  12.01   0.00  11.93      0    0.000     0    0.000    0.000
  0.00  54.32   5.86   0.01  11.94      1    0.002     0    0.000    0.002
  0.00  54.32   5.86   0.01  11.94      1    0.002     0    0.000    0.002
 96.58   0.00   0.00   0.01  11.94      2    0.004     0    0.000    0.004
 96.58   0.00  21.54   0.01  11.94      2    0.004     0    0.000    0.004
  0.00  96.58   0.00   0.01  11.94      3    0.006     0    0.000    0.006
  0.00  96.58  82.32   0.01  11.94      3    0.006     0    0.000    0.006
 10.57   0.00   0.00  10.61  11.94      4    0.009     0    0.000    0.009
 10.57   0.00   0.00  10.61  11.94      4    0.009     0    0.000    0.009
 10.57   0.00  41.35  10.61  11.94      4    0.009     0    0.000    0.009
 10.57   0.00  41.35  10.61  11.94      4    0.009     0    0.000    0.009
  0.00  11.46  40.92  10.61  11.94      5    0.010     0    0.000    0.010
  0.00  11.46  40.92  10.61  11.94      5    0.010     0    0.000    0.010
  0.00  11.46  40.92  10.61  11.94      5    0.010     0    0.000    0.010
  0.00  11.46  93.70  10.61  11.94      6    0.010     0    0.000    0.010
  8.22   0.00   0.00  31.82  11.94      6    0.018     0    0.000    0.018
  8.22   0.00  18.62  31.82  11.94      6    0.018     0    0.000    0.018
  8.22   0.00  18.62  31.82  11.94      6    0.018     0    0.000    0.018
  8.22   0.00  18.62  31.82  11.94      6    0.018     0    0.000    0.018
  8.22   0.00  70.07  31.82  12.06      6    0.018     0    0.000    0.018
  8.22   0.00  70.07  31.82  12.06      6    0.018     0    0.000    0.018
  8.22   0.00  89.85  31.82  12.07      6    0.018     0    0.000    0.018
  8.22   0.00  89.85  31.82  12.07      7    0.018     0    0.000    0.018
  0.00  34.09   0.00  32.41  12.07      7    0.020     0    0.000    0.020
  0.00  34.09  19.26  32.41  12.07      7    0.020     0    0.000    0.020
  0.00  34.09  19.26  32.41  12.07      7    0.020     0    0.000    0.020
  0.00  34.09  53.07  32.41  12.07      7    0.020     0    0.000    0.020
  0.00  34.09  53.07  32.41  12.07      7    0.020     0    0.000    0.020
  0.00  34.09  53.07  32.41  12.07      7    0.020     0    0.000    0.020
  0.00  34.09  79.83  32.41  12.07      7    0.020     0    0.000    0.020
  0.00  34.09  79.83  32.41  12.07      7    0.020     0    0.000    0.020
  1.98   0.00  10.34  43.02  12.07      8    0.023     0    0.000    0.023
  1.98   0.00  10.34  43.02  12.07      8    0.023     0    0.000    0.023
  1.98   0.00  10.34  43.02  12.07      8    0.023     0    0.000    0.023
  1.98   0.00  23.53  43.02  12.07      8    0.023     0    0.000    0.023
  1.98   0.00  23.53  43.02  12.07      8    0.023     0    0.000    0.023
  1.98   0.00  36.71  43.02  12.07      8    0.023     0    0.000    0.023

可以看到只有8次GC.

jstat -gccapacity 18360 

 NGCMN    NGCMX     NGC     S0C   S1C       EC      OGCMN      OGCMX       OGC         OC      PGCMN    PGCMX     PGC       PC     YGC    FGC 
 43456.0 695616.0  43456.0 5376.0 5376.0  32704.0    86912.0  1391296.0    86912.0    86912.0  21248.0  83968.0  21248.0  21248.0      0     0


这里有两个问题:

1.为啥两个测出的GC次数不一样?

2. 如何计算该JVM生存期内的yongGc回收的内存大小?

求指点。

### 使用 SoloPi 测试 App 性能时应关注的内存相关关键指标 在使用 SoloPi 工具测试 App 的性能时,为了全面评估应用的内存表现并发现潜在问题,需重点关注以下几个方面的内存相关指标: #### 1. **Total PSS (Proportional Set Size)** 这是衡量应用程序实际使用的物理内存大小的关键指标之一。它表示进程独占的部分以及与其他进程共享部分按比例分配后的内存总量。通过计算 `Total PSS` 占设备总内存的比例,可以判断应用对系统整体内存的影响程度[^4]。 #### 2. **Private Dirty Memory** 这部分内存是指仅被该应用私有占用且无法交换到磁盘上的脏页数据量。如果 Private Dirty 过高,则可能导致其他应用可用内存减少,进而影响系统的流畅性和稳定性。 #### 3. **RSS (Resident Set Size)** RSS 表示驻留在 RAM 中的应用程序代码和数据的实际数量。虽然 RSS 包含了一些可能未由当前进程单独拥有的共享库区域,但它仍然是一个重要的参考值来了解整个工作集所需的最小内存量。 #### 4. **Heap Size 和 Allocated Heap** 堆大小反映了 Java 堆或 Native 堆的增长情况;已分配堆则显示了目前已被申请但尚未释放的空间总数。当检测到 heap size 不断增大而 allocated heap 并没有相应增加时,可能存在泄漏风险[^2]。 #### 5. **GC Frequency & Duration (Garbage Collection 频率及时长)** 垃圾回收活动频繁或者耗时过久都会显著降低用户体验。因此,在监测过程中也需要注意 GC 发生次数及其平均执行时间是否合理正常范围之内。 #### 6. **Memory Leaks Detection (内存泄露探测)** 利用 SoloPi 提供的相关功能模块定期扫描是否存在长期存在的对象引用链路未能得到清理的情况,从而有效预防因内存溢出而导致崩溃等问题发生。 ```python # 示例 Python 脚本用于模拟获取某些内存指标(假设接口存在) import solo_pi_api as spapi def get_memory_metrics(app_id): metrics = {} memory_data = spapi.get_app_memory_info(app_id) # 获取 Total PSS total_pss = memory_data['total_pss'] metrics['total_pss'] = f"{total_pss} KB" # 计算百分比 device_total_ram_kb = 6093056 # 设备总RAM容量(KB),这里硬编码仅为演示目的 percentage_used = round((total_pss / device_total_ram_kb)*100, 2) metrics['percentage_used'] = str(percentage_used)+'%' return metrics example_metrics = get_memory_metrics('com.example.app') print(example_metrics) ``` 以上代码片段展示了如何借助假想中的 API 来提取特定 APP 的内存信息,并进一步处理成易于理解的形式输出。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值