diff options
author | Florian Frank <flori@ping.de> | 2011-07-04 18:04:14 +0200 |
---|---|---|
committer | Florian Frank <flori@ping.de> | 2011-07-04 18:04:14 +0200 |
commit | 58a54defa3344f94b211b1d3b5e1a6e24e4054b0 (patch) | |
tree | e8d11a478a55f6d317b80b135eefaf3d090d883b /java/src | |
parent | 738a65c873f7ecc82352fbd516aadfec67063fc8 (diff) | |
parent | 1a9725371131300e3230b4b9c14e669d334f4152 (diff) | |
download | json-58a54defa3344f94b211b1d3b5e1a6e24e4054b0.tar.gz |
Merge branch 'fix_memory_leak' of https://github.com/bigfix/json into development
Diffstat (limited to 'java/src')
-rw-r--r-- | java/src/json/ext/Generator.java | 4 | ||||
-rw-r--r-- | java/src/json/ext/GeneratorMethods.java | 11 | ||||
-rw-r--r-- | java/src/json/ext/GeneratorService.java | 7 | ||||
-rw-r--r-- | java/src/json/ext/GeneratorState.java | 6 | ||||
-rw-r--r-- | java/src/json/ext/OptionsReader.java | 4 | ||||
-rw-r--r-- | java/src/json/ext/Parser.java | 14 | ||||
-rw-r--r-- | java/src/json/ext/ParserService.java | 5 | ||||
-rw-r--r-- | java/src/json/ext/RuntimeInfo.java | 44 | ||||
-rw-r--r-- | java/src/json/ext/Utils.java | 2 |
9 files changed, 51 insertions, 46 deletions
diff --git a/java/src/json/ext/Generator.java b/java/src/json/ext/Generator.java index 92fd90e..fbc394f 100644 --- a/java/src/json/ext/Generator.java +++ b/java/src/json/ext/Generator.java @@ -376,9 +376,9 @@ public final class Generator { RubyString src; if (info.encodingsSupported() && - object.encoding(session.getContext()) != info.utf8) { + object.encoding(session.getContext()) != info.utf8.get()) { src = (RubyString)object.encode(session.getContext(), - info.utf8); + info.utf8.get()); } else { src = object; } diff --git a/java/src/json/ext/GeneratorMethods.java b/java/src/json/ext/GeneratorMethods.java index 28a612d..356f2d0 100644 --- a/java/src/json/ext/GeneratorMethods.java +++ b/java/src/json/ext/GeneratorMethods.java @@ -6,6 +6,7 @@ */ package json.ext; +import java.lang.ref.WeakReference; import org.jruby.Ruby; import org.jruby.RubyArray; import org.jruby.RubyBoolean; @@ -45,9 +46,9 @@ class GeneratorMethods { defineMethods(module, "String", RbString.class); defineMethods(module, "TrueClass", RbTrue.class); - info.stringExtendModule = module.defineModuleUnder("String") - .defineModuleUnder("Extend"); - info.stringExtendModule.defineAnnotatedMethods(StringExtend.class); + info.stringExtendModule = new WeakReference<RubyModule>(module.defineModuleUnder("String") + .defineModuleUnder("Extend")); + info.stringExtendModule.get().defineAnnotatedMethods(StringExtend.class); } /** @@ -140,7 +141,7 @@ class GeneratorMethods { RubyHash result = RubyHash.newHash(runtime); IRubyObject createId = RuntimeInfo.forRuntime(runtime) - .jsonModule.callMethod(context, "create_id"); + .jsonModule.get().callMethod(context, "create_id"); result.op_aset(context, createId, self.getMetaClass().to_s()); ByteList bl = self.getByteList(); @@ -158,7 +159,7 @@ class GeneratorMethods { public static IRubyObject included(ThreadContext context, IRubyObject vSelf, IRubyObject module) { RuntimeInfo info = RuntimeInfo.forRuntime(context.getRuntime()); - return module.callMethod(context, "extend", info.stringExtendModule); + return module.callMethod(context, "extend", info.stringExtendModule.get()); } } diff --git a/java/src/json/ext/GeneratorService.java b/java/src/json/ext/GeneratorService.java index b8deb22..2f3b07e 100644 --- a/java/src/json/ext/GeneratorService.java +++ b/java/src/json/ext/GeneratorService.java @@ -7,6 +7,7 @@ package json.ext; import java.io.IOException; +import java.lang.ref.WeakReference; import org.jruby.Ruby; import org.jruby.RubyClass; @@ -23,15 +24,15 @@ public class GeneratorService implements BasicLibraryService { runtime.getLoadService().require("json/common"); RuntimeInfo info = RuntimeInfo.initRuntime(runtime); - info.jsonModule = runtime.defineModule("JSON"); - RubyModule jsonExtModule = info.jsonModule.defineModuleUnder("Ext"); + info.jsonModule = new WeakReference<RubyModule>(runtime.defineModule("JSON")); + RubyModule jsonExtModule = info.jsonModule.get().defineModuleUnder("Ext"); RubyModule generatorModule = jsonExtModule.defineModuleUnder("Generator"); RubyClass stateClass = generatorModule.defineClassUnder("State", runtime.getObject(), GeneratorState.ALLOCATOR); stateClass.defineAnnotatedMethods(GeneratorState.class); - info.generatorStateClass = stateClass; + info.generatorStateClass = new WeakReference<RubyClass>(stateClass); RubyModule generatorMethods = generatorModule.defineModuleUnder("GeneratorMethods"); diff --git a/java/src/json/ext/GeneratorState.java b/java/src/json/ext/GeneratorState.java index dc99000..f04eda2 100644 --- a/java/src/json/ext/GeneratorState.java +++ b/java/src/json/ext/GeneratorState.java @@ -118,7 +118,7 @@ public class GeneratorState extends RubyObject { static GeneratorState fromState(ThreadContext context, RuntimeInfo info, IRubyObject opts) { - RubyClass klass = info.generatorStateClass; + RubyClass klass = info.generatorStateClass.get(); if (opts != null) { // if the given parameter is a Generator::State, return itself if (klass.isInstance(opts)) return (GeneratorState)opts; @@ -382,8 +382,8 @@ public class GeneratorState extends RubyObject { private ByteList prepareByteList(ThreadContext context, IRubyObject value) { RubyString str = value.convertToString(); RuntimeInfo info = RuntimeInfo.forRuntime(context.getRuntime()); - if (info.encodingsSupported() && str.encoding(context) != info.utf8) { - str = (RubyString)str.encode(context, info.utf8); + if (info.encodingsSupported() && str.encoding(context) != info.utf8.get()) { + str = (RubyString)str.encode(context, info.utf8.get()); } return str.getByteList().dup(); } diff --git a/java/src/json/ext/OptionsReader.java b/java/src/json/ext/OptionsReader.java index 018ace4..c9c9c94 100644 --- a/java/src/json/ext/OptionsReader.java +++ b/java/src/json/ext/OptionsReader.java @@ -84,8 +84,8 @@ final class OptionsReader { RubyString str = value.convertToString(); RuntimeInfo info = getRuntimeInfo(); - if (info.encodingsSupported() && str.encoding(context) != info.utf8) { - str = (RubyString)str.encode(context, info.utf8); + if (info.encodingsSupported() && str.encoding(context) != info.utf8.get()) { + str = (RubyString)str.encode(context, info.utf8.get()); } return str; } diff --git a/java/src/json/ext/Parser.java b/java/src/json/ext/Parser.java index 482d5cc..a69a562 100644 --- a/java/src/json/ext/Parser.java +++ b/java/src/json/ext/Parser.java @@ -176,8 +176,8 @@ public class Parser extends RubyObject { if (info.encodingsSupported()) { RubyEncoding encoding = (RubyEncoding)source.encoding(context); - if (encoding != info.ascii8bit) { - return (RubyString)source.encode(context, info.utf8); + if (encoding != info.ascii8bit.get()) { + return (RubyString)source.encode(context, info.utf8.get()); } String sniffedEncoding = sniffByteList(bl); @@ -188,7 +188,7 @@ public class Parser extends RubyObject { String sniffedEncoding = sniffByteList(bl); if (sniffedEncoding == null) return source; // assume UTF-8 Ruby runtime = context.getRuntime(); - return (RubyString)info.jsonModule. + return (RubyString)info.jsonModule.get(). callMethod(context, "iconv", new IRubyObject[] { runtime.newString("utf-8"), @@ -218,7 +218,7 @@ public class Parser extends RubyObject { private RubyString reinterpretEncoding(ThreadContext context, RubyString str, String sniffedEncoding) { RubyEncoding actualEncoding = info.getEncoding(context, sniffedEncoding); - RubyEncoding targetEncoding = info.utf8; + RubyEncoding targetEncoding = info.utf8.get(); RubyString dup = (RubyString)str.dup(); dup.force_encoding(context, actualEncoding); return (RubyString)dup.encode_bang(context, targetEncoding); @@ -251,7 +251,7 @@ public class Parser extends RubyObject { * set to <code>nil</code> or <code>false</code>, and a String if not. */ private RubyString getCreateId(ThreadContext context) { - IRubyObject v = info.jsonModule.callMethod(context, "create_id"); + IRubyObject v = info.jsonModule.get().callMethod(context, "create_id"); return v.isTrue() ? v.convertToString() : null; } @@ -1993,7 +1993,7 @@ case 5: IRubyObject vKlassName = result.op_aref(context, parser.createId); if (!vKlassName.isNil()) { // might throw ArgumentError, we let it propagate - IRubyObject klass = parser.info.jsonModule. + IRubyObject klass = parser.info.jsonModule.get(). callMethod(context, "deep_const_get", vKlassName); if (klass.respondsTo("json_creatable?") && klass.callMethod(context, "json_creatable?").isTrue()) { @@ -2283,7 +2283,7 @@ case 5: * @param name The constant name */ private IRubyObject getConstant(String name) { - return parser.info.jsonModule.getConstant(name); + return parser.info.jsonModule.get().getConstant(name); } private RaiseException newException(String className, String message) { diff --git a/java/src/json/ext/ParserService.java b/java/src/json/ext/ParserService.java index e0805a7..f2ecae1 100644 --- a/java/src/json/ext/ParserService.java +++ b/java/src/json/ext/ParserService.java @@ -7,6 +7,7 @@ package json.ext; import java.io.IOException; +import java.lang.ref.WeakReference; import org.jruby.Ruby; import org.jruby.RubyClass; @@ -23,8 +24,8 @@ public class ParserService implements BasicLibraryService { runtime.getLoadService().require("json/common"); RuntimeInfo info = RuntimeInfo.initRuntime(runtime); - info.jsonModule = runtime.defineModule("JSON"); - RubyModule jsonExtModule = info.jsonModule.defineModuleUnder("Ext"); + info.jsonModule = new WeakReference<RubyModule>(runtime.defineModule("JSON")); + RubyModule jsonExtModule = info.jsonModule.get().defineModuleUnder("Ext"); RubyClass parserClass = jsonExtModule.defineClassUnder("Parser", runtime.getObject(), Parser.ALLOCATOR); diff --git a/java/src/json/ext/RuntimeInfo.java b/java/src/json/ext/RuntimeInfo.java index f446afe..5de5740 100644 --- a/java/src/json/ext/RuntimeInfo.java +++ b/java/src/json/ext/RuntimeInfo.java @@ -27,19 +27,21 @@ final class RuntimeInfo { private static Map<Ruby, RuntimeInfo> runtimes; // these fields are filled by the service loaders + // Use WeakReferences so that RuntimeInfo doesn't indirectly hold a hard reference to + // the Ruby runtime object, which would cause memory leaks in the runtimes map above. /** JSON */ - RubyModule jsonModule; + WeakReference<RubyModule> jsonModule; /** JSON::Ext::Generator::GeneratorMethods::String::Extend */ - RubyModule stringExtendModule; + WeakReference<RubyModule> stringExtendModule; /** JSON::Ext::Generator::State */ - RubyClass generatorStateClass; + WeakReference<RubyClass> generatorStateClass; /** JSON::SAFE_STATE_PROTOTYPE */ - GeneratorState safeStatePrototype; + WeakReference<GeneratorState> safeStatePrototype; - final RubyEncoding utf8; - final RubyEncoding ascii8bit; + final WeakReference<RubyEncoding> utf8; + final WeakReference<RubyEncoding> ascii8bit; // other encodings - private final Map<String, RubyEncoding> encodings; + private final Map<String, WeakReference<RubyEncoding>> encodings; private RuntimeInfo(Ruby runtime) { RubyClass encodingClass = runtime.getEncoding(); @@ -49,11 +51,11 @@ final class RuntimeInfo { } else { ThreadContext context = runtime.getCurrentContext(); - utf8 = (RubyEncoding)RubyEncoding.find(context, - encodingClass, runtime.newString("utf-8")); - ascii8bit = (RubyEncoding)RubyEncoding.find(context, - encodingClass, runtime.newString("ascii-8bit")); - encodings = new HashMap<String, RubyEncoding>(); + utf8 = new WeakReference<RubyEncoding>((RubyEncoding)RubyEncoding.find(context, + encodingClass, runtime.newString("utf-8"))); + ascii8bit = new WeakReference<RubyEncoding>((RubyEncoding)RubyEncoding.find(context, + encodingClass, runtime.newString("ascii-8bit"))); + encodings = new HashMap<String, WeakReference<RubyEncoding>>(); } } @@ -90,30 +92,30 @@ final class RuntimeInfo { } public boolean encodingsSupported() { - return utf8 != null; + return utf8 != null && utf8.get() != null; } public RubyEncoding getEncoding(ThreadContext context, String name) { synchronized (encodings) { - RubyEncoding encoding = encodings.get(name); + WeakReference<RubyEncoding> encoding = encodings.get(name); if (encoding == null) { Ruby runtime = context.getRuntime(); - encoding = (RubyEncoding)RubyEncoding.find(context, - runtime.getEncoding(), runtime.newString(name)); + encoding = new WeakReference<RubyEncoding>((RubyEncoding)RubyEncoding.find(context, + runtime.getEncoding(), runtime.newString(name))); encodings.put(name, encoding); } - return encoding; + return encoding.get(); } } public GeneratorState getSafeStatePrototype(ThreadContext context) { if (safeStatePrototype == null) { - IRubyObject value = jsonModule.getConstant("SAFE_STATE_PROTOTYPE"); + IRubyObject value = jsonModule.get().getConstant("SAFE_STATE_PROTOTYPE"); if (!(value instanceof GeneratorState)) { - throw context.getRuntime().newTypeError(value, generatorStateClass); + throw context.getRuntime().newTypeError(value, generatorStateClass.get()); } - safeStatePrototype = (GeneratorState)value; + safeStatePrototype = new WeakReference<GeneratorState>((GeneratorState)value); } - return safeStatePrototype; + return safeStatePrototype.get(); } } diff --git a/java/src/json/ext/Utils.java b/java/src/json/ext/Utils.java index 7a1dfee..f52ac8d 100644 --- a/java/src/json/ext/Utils.java +++ b/java/src/json/ext/Utils.java @@ -66,7 +66,7 @@ final class Utils { static RaiseException newException(ThreadContext context, String className, RubyString message) { RuntimeInfo info = RuntimeInfo.forRuntime(context.getRuntime()); - RubyClass klazz = info.jsonModule.getClass(className); + RubyClass klazz = info.jsonModule.get().getClass(className); RubyException excptn = (RubyException)klazz.newInstance(context, new IRubyObject[] {message}, Block.NULL_BLOCK); |