【发布时间】:2015-01-27 11:16:59
【问题描述】:
我正在开发一个需要与 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();
}
}
尴尬(对我而言),在线程例程 (tempBytesWritten = fc.write(ByteBuffer.wrap(randomByteString.getBytes()));) 的第 30 行,第二个线程 ("pool-1-thread-2") 启动异常,退出,第一个线程 ("pool -1-thread-1") 继续(实际上是开始)正常执行。
当 JVM 完成为那个大的 String 分配空间时,应用程序正在使用 33MB 的堆。从代码中可以看出,thatString 只创建了一次,然后在两个线程中都使用了多次。
线程不应该只使用对String 的引用而不是复制它吗? (在这种情况下,这将超过 40MB 的限额)。
我还必须指出,在 Gingerbread (previous research) 上增加这个堆空间是不可能的(或者至少似乎是,就我的理解而言)。
我有什么遗漏吗? 非常感谢任何帮助。
【问题讨论】:
标签: java android multithreading out-of-memory heap-memory