Skip to content

Commit

Permalink
Merge pull request #8405 from pshipton/stringbuffergrowth
Browse files Browse the repository at this point in the history
Grow StringBuffer and StringBuilder aggressively from 1G to 2G
  • Loading branch information
keithc-ca committed Jan 30, 2020
2 parents 3f8a2c1 + 0301b81 commit a740844
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 4 deletions.
11 changes: 10 additions & 1 deletion jcl/src/java.base/share/classes/java/lang/StringBuffer.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
package java.lang;

/*******************************************************************************
* Copyright (c) 1998, 2019 IBM Corp. and others
* Copyright (c) 1998, 2020 IBM Corp. and others
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which accompanies this
Expand Down Expand Up @@ -60,6 +60,8 @@ public final class StringBuffer extends AbstractStringBuilder implements Seriali


private static boolean TOSTRING_COPY_BUFFER_ENABLED = false;
private static boolean growAggressively = false;


// Used to access compression related helper methods
private static final com.ibm.jit.JITHelpers helpers = com.ibm.jit.JITHelpers.getHelpers();
Expand Down Expand Up @@ -761,6 +763,10 @@ private void ensureCapacityImpl(int min) {

int newCapacity = (currentCapacity << 1) + 2;

if (growAggressively && (newCapacity < currentCapacity)) {
newCapacity = Integer.MAX_VALUE;
}

int newLength = min > newCapacity ? min : newCapacity;

// Check if the StringBuilder is compressed
Expand Down Expand Up @@ -1709,6 +1715,9 @@ public synchronized String substring(int start, int end) {
static void initFromSystemProperties(Properties props) {
String prop = props.getProperty("java.lang.string.create.unique"); //$NON-NLS-1$
TOSTRING_COPY_BUFFER_ENABLED = "true".equals(prop) || "StringBuffer".equals(prop); //$NON-NLS-1$ //$NON-NLS-2$

String growAggressivelyProperty = props.getProperty("java.lang.stringBufferAndBuilder.growAggressively"); //$NON-NLS-1$
growAggressively = "".equals(growAggressivelyProperty) || "true".equalsIgnoreCase(growAggressivelyProperty); //$NON-NLS-1$ //$NON-NLS-2$
}

/**
Expand Down
10 changes: 9 additions & 1 deletion jcl/src/java.base/share/classes/java/lang/StringBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
package java.lang;

/*******************************************************************************
* Copyright (c) 2005, 2019 IBM Corp. and others
* Copyright (c) 2005, 2020 IBM Corp. and others
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which accompanies this
Expand Down Expand Up @@ -64,6 +64,7 @@ public final class StringBuilder extends AbstractStringBuilder implements Serial


private static boolean TOSTRING_COPY_BUFFER_ENABLED = false;
private static boolean growAggressively = false;

// Used to access compression related helper methods
private static final com.ibm.jit.JITHelpers helpers = com.ibm.jit.JITHelpers.getHelpers();
Expand Down Expand Up @@ -760,6 +761,10 @@ private void ensureCapacityImpl(int min) {

int newCapacity = (currentCapacity << 1) + 2;

if (growAggressively && (newCapacity < currentCapacity)) {
newCapacity = Integer.MAX_VALUE;
}

int newLength = min > newCapacity ? min : newCapacity;

// Check if the StringBuilder is compressed
Expand Down Expand Up @@ -1709,6 +1714,9 @@ public String substring(int start, int end) {
static void initFromSystemProperties(Properties props) {
String prop = props.getProperty("java.lang.string.create.unique"); //$NON-NLS-1$
TOSTRING_COPY_BUFFER_ENABLED = "true".equals(prop) || "StringBuilder".equals(prop); //$NON-NLS-1$ //$NON-NLS-2$

String growAggressivelyProperty = props.getProperty("java.lang.stringBufferAndBuilder.growAggressively"); //$NON-NLS-1$
growAggressively = "".equals(growAggressivelyProperty) || "true".equalsIgnoreCase(growAggressivelyProperty); //$NON-NLS-1$ //$NON-NLS-2$
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>

<!--
Copyright (c) 2009, 2019 IBM Corp. and others
Copyright (c) 2009, 2020 IBM Corp. and others
This program and the accompanying materials are made available under
the terms of the Eclipse Public License 2.0 which accompanies this
Expand Down Expand Up @@ -545,6 +545,12 @@
<command>$EXE$ -Xjit:count=0,disableZ15 -version</command>
<output regex="no" type="success">version</output>
</test>

<test id="Test StringBuffer/StringBuilder growth">
<command>$EXE$ -Xdump:none -Xmx7g -Djava.lang.stringBufferAndBuilder.growAggressively -cp $Q$$JARPATH$$Q$ TestStringBufferAndBuilderGrowth</command>
<output regex="no" type="success">StringBuffer capacity=2147483647 StringBuilder capacity=2147483647</output>
<output regex="no" type="success">Option too large</output>
</test>

</suite>

Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>

<!--
Copyright (c) 2016, 2019 IBM Corp. and others
Copyright (c) 2016, 2020 IBM Corp. and others
This program and the accompanying materials are made available under
the terms of the Eclipse Public License 2.0 which accompanies this
Expand All @@ -26,6 +26,7 @@
<test>
<testCaseName>cmdLineTest_J9test_SE80</testCaseName>
<command>$(JAVA_COMMAND) -Xdump $(JVM_OPTIONS) -DFIBJAR=$(Q)$(JVM_TEST_ROOT)$(D)functional$(D)cmdLineTests$(D)utils$(D)utils.jar$(Q) \
-DJARPATH=$(Q)$(TEST_RESROOT)$(D)cmdLineTest_J9tests.jar$(Q) \
-DTESTDIR=$(Q)$(TEST_RESROOT)$(Q) -DRESJAR=$(CMDLINETESTER_RESJAR) -DEXE=$(SQ)$(JAVA_COMMAND) $(JVM_OPTIONS) -Xdump$(SQ) \
-Xint -jar $(CMDLINETESTER_JAR) \
-config $(Q)$(TEST_RESROOT)$(D)j9tests_Java8.xml$(Q) \
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*******************************************************************************
* Copyright (c) 2020, 2020 IBM Corp. and others
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which accompanies this
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
* or the Apache License, Version 2.0 which accompanies this distribution and
* is available at https://www.apache.org/licenses/LICENSE-2.0.
*
* This Source Code may also be made available under the following
* Secondary Licenses when the conditions for such availability set
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
* General Public License, version 2 with the GNU Classpath
* Exception [1] and GNU General Public License, version 2 with the
* OpenJDK Assembly Exception [2].
*
* [1] https://www.gnu.org/software/classpath/license.html
* [2] http://openjdk.java.net/legal/assembly-exception.html
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
*******************************************************************************/

/**
* @file TestStringBufferAndBuilderGrowth.java
* @brief Grows a StringBuffer and StringBuilder to Integer.MAX_VALUE
*/
public class TestStringBufferAndBuilderGrowth {

public static void main(String[] args) {
char[] cbuf = new char[Integer.MAX_VALUE / 32];

// Create a StringBuffer big enough that the default algorithm to
// grow it will overflow Integer.MAX_VALUE. Some smaller sizes could
// be used without affecting the test, such as the default size, but
// starting it big avoids unnecessary copying so the test runs faster.
StringBuffer sbuf = new StringBuffer((Integer.MAX_VALUE / 2) + 1);
// 17 iterations adds approximately 1G + 64M (minus a few bytes)
// to the Buffer, causing it to grow.
for (int i = 0; i < 17; i++) {
try {
sbuf.append(cbuf);
} catch (OutOfMemoryError e) {
System.out.println("OOM StringBuffer occurred iteration " + i);
return;
}
}
int sbufCapacity = sbuf.capacity();
// sbuf is no longer used after this point and will be GCed. Nulling it
// isn't technically required for OpenJ9, but make it explicit for clarity.
sbuf = null;

// Duplicate the above test for StringBuilder.
StringBuilder sbld = new StringBuilder((Integer.MAX_VALUE / 2) + 1);
for (int i = 0; i < 17; i++) {
try {
sbld.append(cbuf);
} catch (OutOfMemoryError e) {
System.out.println("OOM StringBuilder occurred iteration " + i);
return;
}
}
int sbldCapacity = sbld.capacity();

System.out.println("StringBuffer capacity=" + sbufCapacity + " StringBuilder capacity=" + sbldCapacity);
}
}

0 comments on commit a740844

Please sign in to comment.