1

我有一个简单的问题。

byte[] responseData = ...;
String str = new String(responseData);
String withKey = "{\"Abcd\":" + str + "}";

在上面的代码中,这三行是否占用了 3X 内存。例如,如果 responseData 为 1mb,则第 2 行将占用额外的 1mb 内存,然后第 3 行将占用额外的 1mb + xx。这是真的?如果没有,那么它将如何工作。如果是,那么解决此问题的最佳方法是什么。StringBuffer 在这里有帮助吗?

4

5 回答 5

4

是的,这听起来很对。可能更多,因为您的 1MB 字节数组需要转换为 UTF-16,因此根据编码,它可能更大(如果输入是 ASCII,则为 2MB)。

请注意,一旦使用它的变量超出范围,垃圾收集器就可以回收内存。您可以将它们设置为null尽可能早,以帮助它尽可能及时(例如responseData = null;在您构建字符串之后)。

如果是,那么解决此问题的最佳方法是什么

“修复”意味着一个问题。如果你有足够的内存没有问题。

问题是我收到 OutOfMemoryException 因为来自服务器的 byte[] 数据很大,

如果你不这样做,你必须考虑一个更好的替代方案来在内存中保留一个 1MB 的字符串。也许您可以从文件中流式传输数据?还是直接处理字节数组?这是什么数据?

于 2013-07-30T02:04:03.280 回答
1

The problem is that I am getting OutOfMemoryException as the byte[] data coming from server is quite big, thats why I need to figure it out first that am I doing something wrong ....

Yes. Well basically your fundamental problem is that you are trying to hold the entire string in memory at one time. This is always going to fail for a sufficiently large string ... even if you code it in the most optimal memory efficient fashion possible. (And that would be complicated in itself.)

The ultimate solution (i.e. the one that "scales") is to do one of the following:

  • stream the data to the file system, or

  • process it in such a way that you don't need ever need the entire "string" to be represented.


You asked if StringBuffer will help. It might help a bit ... provided that you use it correctly. The trick is to make sure that you preallocate the StringBuffer (actually a StringBuilder is better!!) to be big enough to hold all of the characters required. Then copy data into it using a charset decoder (directly or using a Reader pipeline).

But even with optimal coding, you are likely to need a peak of 3 times the size of your input byte[].


Note that your OOME problem is probably nothing to do with GC or storage leaks. It is actually about the fundamental space requirements of the data types you are using ... and the fact that Java does not offer a "string of bytes" data type.

于 2013-07-30T02:16:10.903 回答
0

There is no such OutOfMemoryException in my apidocs. If it's OutOfMemoryError, especially on the server-side, you definitely got a problem.

When you receive big requests from clients, those String related statements are not the first problem. Reducing 3X to 1X is not the solution.

I'm sorry I can't help without any further codes.

Use back-end storage

You should not store the whole request body on byte[]. You can store them directly on any back-end storage such as a local file, a remote database, or cloud storage.

I would

copy stream from request to back-end with small chunked buffer

Use streams

If can use Streams not Objects.

I would

response.getWriter().write("{\"Abcd\":");
copy <your back-end stored data as stream>);
response.getWriter().write("}");
于 2013-07-30T02:16:27.793 回答
0

是的,如果您对已有的代码使用 Stringbuffer,您将在最后一步节省 1mb 的堆空间。但是,考虑到您拥有的数据的大小,我建议您使用一种外部存储器算法,您只需将部分数据放入内存,对其进行处理并将其放回存储中。

于 2013-07-30T02:28:09.690 回答
0

正如其他人所提到的,你真的应该尽量不要在你的移动应用程序中使用这么大的对象,而流媒体应该是你最好的解决方案。

也就是说,有一些技术可以减少您的应用程序现在使用的内存量:

  1. 如果可能的话完全删除byte[] responseData,所以它使用的内存可以尽快释放(假设它没有在其他任何地方使用)
  2. 首先创建最大的字符串,然后substring()是它,Android 使用 Apache Harmony 作为其标准 Java 库实现。如果您检查它的 String 类实现,您会发现它substring()是通过创建一个新的 String 对象来实现的,该对象具有与原始数据正确的开始和结束偏移量,并且不会创建重复副本。因此,执行以下操作会将整体内存消耗至少减少 1/3

    String withKey = StringBuilder().append("{\"Abcd\").append(str).append("}").toString(); String str = withKey.substring("{\"Abcd\".length (), withKey.length()-"}".length());

  3. 永远不要"{\"Abcd\":" + str + "}"对大字符串使用类似的东西,在引擎盖下“string_a”+“string_b”被实现为新的StringBuilder().append("string_a").append("string_b").toString();,所以你隐含地创建了两个(或者如果编译器是市场,至少一个)StringBuilders。对于大字符串,最好由您自己接管此过程,因为您对程序有深入的领域知识,而编译器没有,并且知道如何最好地操作字符串。

于 2013-07-30T03:22:40.000 回答