Java下得到ArrayList<String>占用内存大小的方法

刚需:压测时需要占用较大的内存,但使用ArrayList<String>时,无法获得每次调用占用的内存大小.

问题:Java中List的实际申请长度并不是size()取到的长度,而且,每次String申请的内存地址空间和主机有关,诸多因素导致计算估值并不是很准确

参考方案如下

代码

Runtime r = Runtime.getRuntime();
long startRAM = r.freeMemory();
List<String> listRAM = new ArrayList<>();
int loopTimes = 1000000;
String string = "摘抄自出师表…………太长了,不粘在这里";
for(int i = 0;i < loopTimes;i++) {
	listRAM.add(string);
}
long endRAM = r.freeMemory();
Field f = ArrayList.class.getDeclaredField("elementData");
f.setAccessible(true);
Object[] o = (Object[]) f.get(listRAM);

 方案1 使用Runtime内存管理类

String result = "测试RAM结束,测试占用内存空间约为 : " + (startRAM - endRAM);
System.out.println(result);

 方案2 反射的方式查询ArrayList的实际申请长度,然后按照每个字符串申请了2字节进行计算

result = "测试RAM结束,测试占用内存空间约为 : " + ((long)o.length * (long)string.length() * 2);
System.out.println(result);

 方案3 反射的方式查询ArrayList的实际申请长度,然后取字符串的字节数组长度计算

result = "测试RAM结束,测试占用内存空间约为 : " + ((long)o.length * (long)string.getBytes().length);
System.out.println(result);

结果(不同的方案之间差异较大):

测试RAM结束,测试占用内存空间约为 : 14016896
测试RAM结束,测试占用内存空间约为 : 1801351734
测试RAM结束,测试占用内存空间约为 : 2702027601

补充:

使用ArrayList创建List数组时,实际长度由elementData进行维护,可使用反射的方法得到List申请的实际长度。

/**
 * Constructs an empty list with an initial capacity of ten.
 */
public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

/**
 * Appends the specified element to the end of this list.
 *
 * @param e element to be appended to this list
 * @return <tt>true</tt> (as specified by {@link Collection#add})
 */
public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}

分析:

方案一:r.freeMemory()方法可以得到当前内存的使用情况,此处取的是空余内存。因此两次空余内存做差,即可得到本次调用占用的内存。但也是模糊数值,仅作为参考,因为不能保证没有其他内存竞争。

方案二:查Java手册可知,Java遵循utf16原则,字符串中的每个字符均占用16位,即2个字节,因此直接乘2。

方案三:获取字符串的byte数组,用其长度直接相乘。而getBytes()方法底层实际是调用了StringCoding.encode(value, 0, value.length)方法,通过判断当前JVM的编码方式,进行字符解析,若未查到编码方式,将按照UTF-8进行编码。

r.totalMemory();
// 得到的输出结果为:126877696

博主此处选用的是第一种方案,因为和参考值比较接近。孰优孰劣,大大们可自行分析。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这是一个Java程序,名为Schedule,用于存储和获取课程安排信息。下面是代码的解释: ```java import java.util.*; // 导入Java工具包 public class Schedule { // 定义一个名为Schedule的类 // Map 用于存储课程安排信息 private Map<String, List<String>> schedule; // 类的构造函数,用于初始化schedule public Schedule() { this.schedule = new HashMap<>(); } // 添加课程信息 public void addSchedule(String time, String course, String classroom) { if (schedule.containsKey(time)) { // 判断时间是否已经被占用 List<String> courses = schedule.get(time); // 获取该时间段已经占用的课程信息 if (courses.contains(course) || courses.contains(classroom)) { // 判断该课程或教室是否已经被占用 System.out.println("Error: Course or classroom already scheduled at this time."); } else { courses.add(course); courses.add(classroom); schedule.put(time, courses); // 将课程信息添加到schedule中 System.out.println("Schedule added successfully."); } } else { List<String> courses = new ArrayList<>(); courses.add(course); courses.add(classroom); schedule.put(time, courses); // 将课程信息添加到schedule中 System.out.println("Schedule added successfully."); } } // 获取课程安排信息 public List<String> getSchedule(String time) { if (schedule.containsKey(time)) { return schedule.get(time); // 返回该时间段的课程信息 } else { return null; // 如果该时间段没有课程信息,则返回null } } // 主函数 public static void main(String[] args) { Schedule schedule = new Schedule(); // 创建一个Schedule对象 schedule.addSchedule("Monday 9:00", "Math", "Room 101"); // 添加课程信息 schedule.addSchedule("Monday 9:00", "Physics", "Room 102"); schedule.addSchedule("Monday 10:00", "English", "Room 103"); List<String> monday_9 = schedule.getSchedule("Monday 9:00"); // 获取课程信息 System.out.println("Monday 9:00 schedule: " + monday_9.toString()); // 打印课程信息 } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值