Skip to content

Commit 7712855

Browse files
authored
Use @scanner << readline instead of @scanner.string = @scanner.rest + readline (#107)
## Why JRuby's `StringScanner#<<` and `StringScanner#scan` OutOfMemoryError has been resolved in strscan gem 3.0.9. ruby/strscan#83 ## Benchmark ``` RUBYLIB= BUNDLER_ORIG_RUBYLIB= /Users/naitoh/.rbenv/versions/3.3.0/bin/ruby -v -S benchmark-driver /Users/naitoh/ghq/github.com/naitoh/rexml/benchmark/parse.yaml ruby 3.3.0 (2023-12-25 revision 5124f9ac75) [arm64-darwin22] Calculating ------------------------------------- before after before(YJIT) after(YJIT) dom 10.958 11.044 16.615 16.783 i/s - 100.000 times in 9.126104s 9.055023s 6.018799s 5.958437s sax 29.624 29.609 44.390 45.370 i/s - 100.000 times in 3.375641s 3.377372s 2.252774s 2.204080s pull 33.868 34.695 51.173 53.492 i/s - 100.000 times in 2.952679s 2.882229s 1.954138s 1.869422s stream 31.719 32.351 43.604 45.403 i/s - 100.000 times in 3.152713s 3.091052s 2.293356s 2.202514s Comparison: dom after(YJIT): 16.8 i/s before(YJIT): 16.6 i/s - 1.01x slower after: 11.0 i/s - 1.52x slower before: 11.0 i/s - 1.53x slower sax after(YJIT): 45.4 i/s before(YJIT): 44.4 i/s - 1.02x slower before: 29.6 i/s - 1.53x slower after: 29.6 i/s - 1.53x slower pull after(YJIT): 53.5 i/s before(YJIT): 51.2 i/s - 1.05x slower after: 34.7 i/s - 1.54x slower before: 33.9 i/s - 1.58x slower stream after(YJIT): 45.4 i/s before(YJIT): 43.6 i/s - 1.04x slower after: 32.4 i/s - 1.40x slower before: 31.7 i/s - 1.43x slower ``` - YJIT=ON : 1.01x - 1.05x faster - YJIT=OFF : 1.00x - 1.02x faster
1 parent 83ca5c4 commit 7712855

File tree

3 files changed

+4
-8
lines changed

3 files changed

+4
-8
lines changed

benchmark/parse.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ contexts:
66
prelude: require 'rexml'
77
- name: master
88
gems:
9-
strscan: 3.0.8
9+
strscan: 3.0.9
1010
prelude: |
1111
$LOAD_PATH.unshift(File.expand_path("lib"))
1212
require 'rexml'
@@ -19,7 +19,7 @@ contexts:
1919
RubyVM::YJIT.enable
2020
- name: master(YJIT)
2121
gems:
22-
strscan: 3.0.8
22+
strscan: 3.0.9
2323
prelude: |
2424
$LOAD_PATH.unshift(File.expand_path("lib"))
2525
require 'rexml'

lib/rexml/source.rb

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -149,11 +149,7 @@ def initialize(arg, block_size=500, encoding=nil)
149149

150150
def read
151151
begin
152-
# NOTE: `@scanner << readline` does not free memory, so when parsing huge XML in JRuby's DOM,
153-
# out-of-memory error `Java::JavaLang::OutOfMemoryError: Java heap space` occurs.
154-
# `@scanner.string = @scanner.rest + readline` frees memory that is already consumed
155-
# and avoids this problem.
156-
@scanner.string = @scanner.rest + readline
152+
@scanner << readline
157153
rescue Exception, NameError
158154
@source = nil
159155
end

rexml.gemspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ Gem::Specification.new do |spec|
5555

5656
spec.required_ruby_version = '>= 2.5.0'
5757

58-
spec.add_runtime_dependency("strscan", ">= 3.0.8")
58+
spec.add_runtime_dependency("strscan", ">= 3.0.9")
5959

6060
spec.add_development_dependency "benchmark_driver"
6161
spec.add_development_dependency "bundler"

0 commit comments

Comments
 (0)