gpt4 book ai didi

java - 多线程时出现 OutOfMemory 异常...堆空间?

转载 作者:行者123 更新时间:2023-12-01 12:12:33 26 4
gpt4 key购买 nike

我正在开发一个需要与 Android 2.3 (Gingerbread) 兼容的应用程序,我用于开发测试的设备是运行 Android 2.3.6 的 Motorola Atrix MB860。

在此设备中,我获得了大约 40MB 的最大堆空间,据我所知,我的应用程序使用了大约 33MB,但无论如何我都会遇到 OutOfMemoryError 异常。

基本上,我的代码中与此问题相关的部分创建了一个大的String(8MB - 我知道它相当大,但如果它太小,则无法满足其中一个要求)然后继续创建2个线程,使用该字符串并发写入某个内存空间。

这是代码:

    // Create random string
StringBuilder sb = new StringBuilder();
sb.ensureCapacity(8388608); // ensuring 8 MB is allocated on the heap for the StringBuilder object
for (long i = 0; i < DATA_SIZE; i++) {
char c = chars[new Random().nextInt(chars.length)];
sb.append(c);
}
String randomByteString = sb.toString();

ExecutorService executor = Executors.newFixedThreadPool(2);
for (int i = 0; i < 2; i++) {
Runnable worker = new SlidingBubbles(param1, param2, randomByteString)
executor.execute(worker);
}
// This will make the executor accept no new threads
// and finish all existing threads in the queue
executor.shutdown();

// Wait until all threads are finish
while(!executor.isTerminated()) {
// wait for bubble threads to finish working...
}

以及线程的例程:

private class SlidingBubbles implements Runnable {
private int param1, param2;
private String randomByteString;
private final Object mSignal = new Object();
private volatile long tempBytesWritten = 0;
private volatile long totalBytesWritten = 0;

public SlidingBubbles(int param1, int param2, String randomByteString) {
this.param1= param1;
this.param2= param2;
this.randomByteString = randomByteString;
}

private void doIt() {
File file = null;
RandomAccessFile randomAccessFile = null;
FileChannel fc = null;

try {
while(param1> 0) {
// Instantiate the 1st bubble file
file = new File(TARGET_DIR, String.valueOf(Calendar.getInstance().getTimeInMillis()));

while(param2 > 0) {
randomAccessFile = new RandomAccessFile(file, "rwd");
fc = randomAccessFile.getChannel();

fc.position(fc.size());
synchronized (mSignal) {
tempBytesWritten = fc.write(ByteBuffer.wrap(randomByteString.getBytes()));

totalBytesWritten += tempBytesWritten;
}

// some other things that don't matter
}

@Override
public void run() {
wipe();
}
}

对我来说,尴尬的是,在线程例程的第 30 行 (tempBytesWritten = fc.write(ByteBuffer.wrap(randomByteString.getBytes()));),第二个线程 ("pool-1-thread-2”)启动异常,退出,第一个线程(“pool-1-thread-1”)继续(实际上,开始)正常执行。当 JVM 完成为该大 String 分配空间时,应用程序正在使用 33MB 的堆。正如您从代码中看到的,String 仅创建一次,但随后在两个线程中多次使用。

线程不应该只使用对String的引用而不是复制它吗? (在这种情况下,这将超过 40MB 的限额)。

我还必须指出,增加 Gingerbread ( previous research ) 上的堆空间是不可能的(或者至少看起来是,据我的理解)。

我有什么遗漏的吗?非常感谢任何帮助。

最佳答案

您可以静态拥有 8MB 数据一次,并且永远不会创建它的副本。在 Android 上,StringBuilderString 共享内部 char[],但 String#getBytes() 创建一个副本每次的数据。

我假设您的字符是纯 ASCII,当它们更特殊时,这无法正常工作。

Random random = new Random(); // once!
byte[] data = new byte[8388608];
for (int i = 0; i < data.length; i++) {
data[i] = (byte) chars[random.nextInt(chars.length)];
}

上面将创建一次数据而无需复制。另请注意 new Random() 8388608?循环中的次数也会导致大量内存使用,但它们应该很快被垃圾收集。

当你这样做时

    public SlidingBubbles(int param1, int param2, byte[] data) {
...
synchronized (mSignal) {
tempBytesWritten = fc.write(ByteBuffer.wrap(data));

您不再创建该数据的副本,ByteBuffer.wrap 不会创建该数据的副本。无论您做什么,请将完成的 byte[] 传递给 SlidingBubbles

P.s: while(!executor.isTermminate()) { 是错误的方法,有一个方法:How to wait for all threads to finish, using ExecutorService?

关于java - 多线程时出现 OutOfMemory 异常...堆空间?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27194708/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com