Java 使用StringBuilder处理csv文件以节省堆空间
我正在读一个csv文件,它有大约50000行和1.1MiB大小,并且可以变大 在代码1中,我使用字符串处理csv,而在代码2中,我使用StringBuilder,只有一个线程执行代码,因此没有并发问题 使用StringBuilder比使用普通字符串类更难阅读代码 我是否过早地在Code2中使用StringBuilder进行优化以节省一点堆空间和内存 代码1Java 使用StringBuilder处理csv文件以节省堆空间,java,heap,stringbuilder,Java,Heap,Stringbuilder,我正在读一个csv文件,它有大约50000行和1.1MiB大小,并且可以变大 在代码1中,我使用字符串处理csv,而在代码2中,我使用StringBuilder,只有一个线程执行代码,因此没有并发问题 使用StringBuilder比使用普通字符串类更难阅读代码 我是否过早地在Code2中使用StringBuilder进行优化以节省一点堆空间和内存 代码1 fr = new FileReader(file); BufferedReader read
fr = new FileReader(file);
BufferedReader reader = new BufferedReader(fr);
String line = reader.readLine();
while ( line != null )
{
int separator = line.indexOf(',');
String symbol = line.substring(0, seperator);
int begin = separator;
separator = line.indexOf(',', begin+1);
String price = line.substring(begin+1, seperator);
// Publish this update
publisher.publishQuote(symbol, price);
// Read the next line of fake update data
line = reader.readLine();
}
代码2
编辑
我消除了toString调用,因此生成的字符串对象会更少
代码3
另外,原始代码是从下载的,Code2的效率实际上低于Code1,因为每次调用stringBuilder.toString时,除了现有的stringBuilder对象之外,您还创建了一个新的java.lang.String实例。由于对象创建开销,这在空间和时间方面效率较低
将readLine的内容直接分配给字符串,然后拆分该字符串通常就足够了。您也可以考虑使用类。
节省内存提示
如果在输入中遇到多个重复令牌,请考虑使用String .In来确保每个相同的标记引用同一个字符串对象;e、 g
String[] tokens = parseTokens(line);
for (String token : tokens) {
// Construct business object referencing interned version of token.
BusinessObject bo = new BusinessObject(token.intern());
// Add business object to collection, etc.
}
Code2的效率实际上不如Code1,因为每次调用stringBuilder.toString时,除了现有的stringBuilder对象之外,您还创建了一个新的java.lang.String实例。由于对象创建开销,这在空间和时间方面效率较低
将readLine的内容直接分配给字符串,然后拆分该字符串通常就足够了。您也可以考虑使用类。
节省内存提示
如果在输入中遇到多个重复令牌,请考虑使用String .In来确保每个相同的标记引用同一个字符串对象;e、 g
String[] tokens = parseTokens(line);
for (String token : tokens) {
// Construct business object referencing interned version of token.
BusinessObject bo = new BusinessObject(token.intern());
// Add business object to collection, etc.
}
我是否过早地在Code2中使用StringBuilder进行优化以节省一点堆空间和内存
很可能:是的。但是,只有一种方法可以找到答案:分析代码
此外,我会使用合适的CSV解析器,而不是您现在正在做的:
我是否过早地在Code2中使用StringBuilder进行优化以节省一点堆空间和内存
很可能:是的。但是,只有一种方法可以找到答案:分析代码
此外,我会使用合适的CSV解析器,而不是您现在正在做的:
优化后的代码会提高应用程序的性能吗?-我的问题
第二个代码示例不会为您节省任何内存和计算时间。我担心您可能误解了StringBuilder的用途,它实际上是用于构建字符串,而不是读取字符串
在循环或第二个代码示例中,每一行都包含表达式stringBuilder.toString,本质上是将缓冲字符串反复转换为字符串对象。实际的字符串操作是针对这些对象执行的。不仅第一个代码示例更容易阅读,而且它的性能肯定与这两个示例相同
我是否过早地使用StringBuilder优化了内容你的问题
除非您分析了您的应用程序,并得出结论,即这些行会导致执行速度显著降低,否则是的。除非您真的确信某些事情会很慢,例如,如果您认识到高计算复杂度,那么在开始进行损害代码可读性的优化之前,您肯定希望进行一些分析
可以对此代码进行何种优化?-我的问题
如果您已经对应用程序进行了描述,并确定这是优化的正确位置,那么您应该考虑查看该类所提供的特性。实际上,这可能会给您带来更好的性能,而分析将告诉您这是否正确,并提供更简单的代码
优化后的代码会提高应用程序的性能吗?-我的问题 第二个代码示例不会为您节省任何内存和计算时间。我担心您可能误解了StringBuilder的用途,它实际上是用于构建字符串,而不是读取字符串 在循环或第二个代码示例中,每一行都包含表达式stringBuilder.toString,本质上是将缓冲字符串反复转换为字符串对象。实际的字符串操作是针对这些对象执行的。不仅第一个代码示例更容易阅读,而且它的性能肯定与这两个示例相同 我是否过早地使用StringBuilder优化了内容你的问题 除非您分析了您的应用程序,并得出结论,即这些行会导致执行速度显著降低,否则是的。除非你真的确信事情会很慢(如你 如果您认识到计算复杂度很高,那么在开始进行损害代码可读性的优化之前,您肯定希望进行一些评测 可以对此代码进行何种优化?-我的问题如果您已经对应用程序进行了描述,并确定这是优化的正确位置,那么您应该考虑查看该类所提供的特性。实际上,这可能会给您带来更好的性能,分析会告诉您这是不是真的,更简单的代码。
通常是这样使用的:StringBuilder sb = new StringBuilder();
sb.append("You").append(" can chain ")
.append(" your ").append(" strings ")
.append("for better readability.");
String myString = sb.toString(); // only call once when you are done
System.out.prinln(sb); // also calls sb.toString().. print myString instead
通常是这样使用的:
StringBuilder sb = new StringBuilder();
sb.append("You").append(" can chain ")
.append(" your ").append(" strings ")
.append("for better readability.");
String myString = sb.toString(); // only call once when you are done
System.out.prinln(sb); // also calls sb.toString().. print myString instead
StringBuilder有几个优点 StringBuffer的操作是同步的,但StringBuilder不是同步的,因此使用StringBuilder将提高单线程场景中的性能 一旦缓冲区被扩展,就可以通过调用对象上的setLength0重用缓冲区。有趣的是,如果您进入调试器并检查StringBuilder的内容,您将看到即使在调用setLength0之后,内容仍然存在。JVM只是重置字符串开头的指针。下次开始追加字符时,指针会移动 如果您不确定字符串的长度,最好使用StringBuilder,因为一旦扩展了缓冲区,就可以将相同的缓冲区用于更小或相等的大小 StringBuffer和StringBuilder在所有操作中几乎相同,只是StringBuffer是同步的,StringBuilder不是
如果没有多线程,那么最好使用StringBuilder。StringBuilder有几个优点 StringBuffer的操作是同步的,但StringBuilder不是同步的,因此使用StringBuilder将提高单线程场景中的性能 一旦缓冲区被扩展,就可以通过调用对象上的setLength0重用缓冲区。有趣的是,如果您进入调试器并检查StringBuilder的内容,您将看到即使在调用setLength0之后,内容仍然存在。JVM只是重置字符串开头的指针。下次开始追加字符时,指针会移动 如果您不确定字符串的长度,最好使用StringBuilder,因为一旦扩展了缓冲区,就可以将相同的缓冲区用于更小或相等的大小 StringBuffer和StringBuilder在所有操作中几乎相同,只是StringBuffer是同步的,StringBuilder不是
如果没有多线程,那么最好使用StringBuilder+1,代码似乎误用了StringBuilder实现1更干净,可能更好。@在上面的代码3中,我删除了StringBuilder.toString调用,这应该会减少创建的字符串对象数。code1使用String类中的功能而不是csv解析器的原因是为了尽量减少堆中的对象数量,因为根据您的经验,此代码在java实时vm上运行,Scanner类的性能会更好吗?@por:我在java中对性能关键的字符串操作的经验不是很全面。如果您真的认为这很重要,您可以在紧密循环中尝试并测量吞吐量。+1,代码似乎误用了StringBuilder实现1更干净,可能更好。@Jørn在上面的代码3中,我删除了StringBuilder.toString调用,这应该会减少创建的字符串对象的数量。code1使用String类中的功能而不是csv解析器的原因是为了尽量减少堆中的对象数量,因为根据您的经验,此代码在java实时vm上运行,Scanner类的性能会更好吗?@por:我在java中对性能关键的字符串操作的经验不是很全面。如果您真的认为这很重要,那么您可以在紧密循环中尝试这两种方法并测量吞吐量。+1请注意,@portoalet,字符串实习不能保证产生任何额外的性能。至少使用秒表进行一些评测,以检查它是否对您的情况有帮助:+1但请注意,@portoalet,不保证字符串实习产生任何额外性能。至少使用秒表进行一些评测,以检查它是否对您的情况有帮助:+1以推荐一个真正的解析器。给出的代码以引号和逗号作为实际值失败。+1我在生产环境中使用ostermiller csv/excelcsv解析器/打印机,这非常好。+1用于推荐真正的解析器。给定的代码失败,实际值为引号和逗号。+1我在生产环境中使用ostermiller csv/excelcsv解析器/打印机,这非常好。即使没有toString调用,Code1也会更有效。为什么?由于String是不可变的,因此String.substring调用将共享底层char[],这是一个比String类本身更大的内存问题。StringBuilder.substring调用必须复制字符[],因为StringBuilder是可变的。因此,Code3涉及更多的字符复制和更多的字符[]实例化 我会更有效率。为什么?由于String是不可变的,因此String.substring调用将共享底层char[],这是一个比String类本身更大的内存问题。StringBuilder.substring调用必须复制字符[],因为StringBuilder是可变的。因此,代码3涉及更多的字符复制和更多的字符[]实例化。