A DESCRIPTION OF THE REQUEST :
The fields nodeListeners and prefListeners are initialized with new empty arrays. It is rather likely that they will stay empty, thus for each preference instance such empty arrays are created.
I propose to create a constant empty array that is used as default value, thus there is just a single array.
Proposed change:
private static final PreferenceChangeListener[] NO_PREF_LISTENERS = new PreferenceChangeListener[0];
private PreferenceChangeListener[] prefListeners = NO_PREF_LISTENERS;
JUSTIFICATION :
I am inspecting potential for memory optimization for an Enterprise software and found in YourKit that the most zero-length array were allocated in AbstractPreferences. The program has 3500 preferences instances, which leads to 100kB memory waste.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
All AbstractPreference instances share a single array of listeners until addNode/PreferenceChangeListener was called.
ACTUAL -
see Description
---------- BEGIN SOURCE ----------
package test;
import java.lang.reflect.Field;
import java.util.prefs.AbstractPreferences;
import java.util.prefs.BackingStoreException;
import org.junit.Assert;
import org.junit.Test;
public class PrefTest {
static class MyPrefs extends AbstractPreferences {
protected MyPrefs() {
super(null, "");
}
protected void putSpi(String key, String value) {}
protected String getSpi(String key) { return null; }
protected void removeSpi(String key) { }
protected void removeNodeSpi() throws BackingStoreException {}
protected String[] keysSpi() throws BackingStoreException { return null; }
protected String[] childrenNamesSpi() throws BackingStoreException { return null;}
protected AbstractPreferences childSpi(String name) { return null; }
protected void syncSpi() throws BackingStoreException { }
protected void flushSpi() throws BackingStoreException {}
}
@Test
public void test_prefListener () throws Exception {
MyPrefs p1 = new MyPrefs();
MyPrefs p2 = new MyPrefs();
Field prefListenersField = AbstractPreferences.class.getDeclaredField("prefListeners");
prefListenersField.setAccessible(true);
Assert.assertSame (prefListenersField.get(p1), prefListenersField.get(p2));
}
}
---------- END SOURCE ----------
The fields nodeListeners and prefListeners are initialized with new empty arrays. It is rather likely that they will stay empty, thus for each preference instance such empty arrays are created.
I propose to create a constant empty array that is used as default value, thus there is just a single array.
Proposed change:
private static final PreferenceChangeListener[] NO_PREF_LISTENERS = new PreferenceChangeListener[0];
private PreferenceChangeListener[] prefListeners = NO_PREF_LISTENERS;
JUSTIFICATION :
I am inspecting potential for memory optimization for an Enterprise software and found in YourKit that the most zero-length array were allocated in AbstractPreferences. The program has 3500 preferences instances, which leads to 100kB memory waste.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
All AbstractPreference instances share a single array of listeners until addNode/PreferenceChangeListener was called.
ACTUAL -
see Description
---------- BEGIN SOURCE ----------
package test;
import java.lang.reflect.Field;
import java.util.prefs.AbstractPreferences;
import java.util.prefs.BackingStoreException;
import org.junit.Assert;
import org.junit.Test;
public class PrefTest {
static class MyPrefs extends AbstractPreferences {
protected MyPrefs() {
super(null, "");
}
protected void putSpi(String key, String value) {}
protected String getSpi(String key) { return null; }
protected void removeSpi(String key) { }
protected void removeNodeSpi() throws BackingStoreException {}
protected String[] keysSpi() throws BackingStoreException { return null; }
protected String[] childrenNamesSpi() throws BackingStoreException { return null;}
protected AbstractPreferences childSpi(String name) { return null; }
protected void syncSpi() throws BackingStoreException { }
protected void flushSpi() throws BackingStoreException {}
}
@Test
public void test_prefListener () throws Exception {
MyPrefs p1 = new MyPrefs();
MyPrefs p2 = new MyPrefs();
Field prefListenersField = AbstractPreferences.class.getDeclaredField("prefListeners");
prefListenersField.setAccessible(true);
Assert.assertSame (prefListenersField.get(p1), prefListenersField.get(p2));
}
}
---------- END SOURCE ----------