Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Speaker Deck
PRO
Sign in
Sign up for free
RMagick, migrate to ImageMagick 7 #RubyKaigi #RubyKaigi2019
Watson
April 18, 2019
Programming
0
8k
RMagick, migrate to ImageMagick 7 #RubyKaigi #RubyKaigi2019
Watson
April 18, 2019
Tweet
Share
More Decks by Watson
See All by Watson
ゲストさんのご紹介
watson
1
540
Magick
watson
0
1.4k
Improve JSON Performance
watson
2
600
fastlane 奮闘記
watson
0
58
How to optimize Ruby internal.
watson
3
2.6k
iOS、AndroidアプリをRubyで
watson
1
370
RubyMotion 2.0
watson
6
2.3k
Differences CRuby/MacRuby/RubyMotion
watson
5
5.3k
Other Decks in Programming
See All in Programming
RFC 9111: HTTP Caching
jxck
0
150
UI Testing of Jetpack Compose Apps, AppDevCon
alexzhukovich
0
120
IE Graduation Certificate
jxck
6
4.7k
Beyond Micro Frontends: Frontend Moduliths for the Enterprise @wad2022
manfredsteyer
PRO
0
130
GDG Seoul IO Extended 2022 - Android Compose
taehwandev
0
290
GitHub Actions を導入した経緯
tamago3keran
1
430
Cross Deviceチームにおけるスマートテレビアプリ開発ってどんな感じ?
cokaholic
0
120
Get Ready for Jakarta EE 10
ivargrimstad
0
1.7k
競プロのすすめ
uya116
0
650
How we run a Realtime Puzzle Fighting Game on AWS Serverless
falken
0
240
【Scrum Fest Osaka 2022】スクラムチームに放り込まれた若手エンジニアの皆さん、どのように技術のキャッチアップをしていくかイメージはついていますか?
miiiki
0
110
Node.jsデザインパターンを読んで
mmmommm
0
2.1k
Featured
See All Featured
Adopting Sorbet at Scale
ufuk
63
7.6k
Building Better People: How to give real-time feedback that sticks.
wjessup
344
17k
Building a Scalable Design System with Sketch
lauravandoore
447
30k
Rails Girls Zürich Keynote
gr2m
86
12k
Ruby is Unlike a Banana
tanoku
91
9.2k
Building an army of robots
kneath
299
40k
What's in a price? How to price your products and services
michaelherold
229
9.4k
Web Components: a chance to create the future
zenorocha
303
40k
How to Ace a Technical Interview
jacobian
265
21k
Practical Orchestrator
shlominoach
178
8.6k
Web development in the modern age
philhawksworth
197
9.3k
Responsive Adventures: Dirty Tricks From The Dark Corners of Front-End
smashingmag
237
19k
Transcript
RMagick, migrate to ImageMagick 7 Shizuo Fujita
self.inspect • @watson1978 • Ubiregi, Inc • Ruby committer •
RMagick maintainer
What's RMagick
"RMagick is an interface between the Ruby programming language and
the ImageMagick image processing library."
Active members ˏmockdeep ˏwatson1978 ˏdlemstra
My Motivation
I want to use Ruby ... •Web programming
I want to use Ruby ... •Web programming •iOS programming
I want to use Ruby ... •Web programming •iOS programming
•Image processing
I want to use Ruby ... •Web programming •iOS programming
•Image processing •Machine learning, etc
I want to use Ruby ... •Web programming •iOS programming
•Image processing •Machine learning, etc To meet crazy great people at Ruby World
Current Status of RMagick
None
Fixed major problems since v2.16.0 •Set up •Memory leaks •SEGVs
Set up problems
Set up problems •macOS (Homebrew) •Windows
macOS (Homebrew)
macOS (Homebrew)
Windows •Ruby has some environments • MingW • MSWin •
Cygwin • Windows Subsystem for Linux
Windows •Ruby has some environments • MingW • MSWin •
Cygwin • Windows Subsystem for Linux
MingW...?
Set up : MingW
Solution https://github.com/oneclick/rubyinstaller2/wiki/For-gem-developers
MingW works
MSWin...?
Set up : MSWin
MSWin supported...? Looks like MSWin supporting code...
Not supported... Why !? For MSWin
MSWin works well
Memory leak
Fixed many memory leaks 55 Closed
Case 1 VALUE Image_shear(VALUE self, VALUE x_shear, VALUE y_shear) {
Image *image, *new_image; ExceptionInfo *exception; image = rm_check_destroyed(self); exception = AcquireExceptionInfo(); new_image = ShearImage(image, NUM2DBL(x_shear), NUM2DBL(y_shear), exception); rm_check_exception(exception, new_image, DestroyOnError); (void) DestroyExceptionInfo(exception); rm_ensure_result(new_image); return rm_image_new(new_image); }
VALUE Image_shear(VALUE self, VALUE x_shear, VALUE y_shear) { Image *image,
*new_image; ExceptionInfo *exception; image = rm_check_destroyed(self); exception = AcquireExceptionInfo(); new_image = ShearImage(image, NUM2DBL(x_shear), NUM2DBL(y_shear), exception); rm_check_exception(exception, new_image, DestroyOnError); (void) DestroyExceptionInfo(exception); rm_ensure_result(new_image); return rm_image_new(new_image); } Case 1 Allocate memory
VALUE Image_shear(VALUE self, VALUE x_shear, VALUE y_shear) { Image *image,
*new_image; ExceptionInfo *exception; image = rm_check_destroyed(self); exception = AcquireExceptionInfo(); new_image = ShearImage(image, NUM2DBL(x_shear), NUM2DBL(y_shear), exception); rm_check_exception(exception, new_image, DestroyOnError); (void) DestroyExceptionInfo(exception); rm_ensure_result(new_image); return rm_image_new(new_image); } Case 1 Allocate memory Destroy memory
VALUE Image_shear(VALUE self, VALUE x_shear, VALUE y_shear) { Image *image,
*new_image; ExceptionInfo *exception; image = rm_check_destroyed(self); exception = AcquireExceptionInfo(); new_image = ShearImage(image, NUM2DBL(x_shear), NUM2DBL(y_shear), exception); rm_check_exception(exception, new_image, DestroyOnError); (void) DestroyExceptionInfo(exception); rm_ensure_result(new_image); return rm_image_new(new_image); } Case 1 Allocate memory Destroy memory Raise exception with unexpected value
VALUE Image_shear(VALUE self, VALUE x_shear, VALUE y_shear) { Image *image,
*new_image; ExceptionInfo *exception; image = rm_check_destroyed(self); exception = AcquireExceptionInfo(); new_image = ShearImage(image, NUM2DBL(x_shear), NUM2DBL(y_shear), exception); rm_check_exception(exception, new_image, DestroyOnError); (void) DestroyExceptionInfo(exception); rm_ensure_result(new_image); return rm_image_new(new_image); } Case 1 Allocate memory Destroy memory Raise exception with unexpected value Unreachable by exception
Case 1: Exception causes Memory Leak image = Magick::Image.read('sample.png').first begin
image.shear('x', 'y') rescue end
Case 2 static VALUE has_attribute(VALUE self, MagickBooleanType....[snip]) { Image *image;
ExceptionInfo *exception; MagickBooleanType r; image = rm_check_destroyed(self); exception = AcquireExceptionInfo(); r = (attr_test)(image, exception); CHECK_EXCEPTION() return r ? Qtrue : Qfalse; }
static VALUE has_attribute(VALUE self, MagickBooleanType....[snip]) { Image *image; ExceptionInfo *exception;
MagickBooleanType r; image = rm_check_destroyed(self); exception = AcquireExceptionInfo(); r = (attr_test)(image, exception); CHECK_EXCEPTION() return r ? Qtrue : Qfalse; } Case 2 Allocate memory
static VALUE has_attribute(VALUE self, MagickBooleanType....[snip]) { Image *image; ExceptionInfo *exception;
MagickBooleanType r; image = rm_check_destroyed(self); exception = AcquireExceptionInfo(); r = (attr_test)(image, exception); CHECK_EXCEPTION() return r ? Qtrue : Qfalse; } Case 2 Allocate memory Missing destroy
Case 2: Missing destroy lead to Memory Leak image =
Magick::Image.read('sample.png').first image.gray?
Case 3 Unnecessary clone API returns NEW image in allocated
memory
Case 3: Memory Leak by incorrect API usage image =
Magick::Image.read('sample.png').first image.sharpen_channel
Case 4
Case 4 Found memory leak in ImageMagick
Case 4
Case 4: Huge software has Memory Leak
How to detect memory leak
Profiler tool
Profiler tool Memory leak detected
Profiler tool
Profiler tool... •Detects at executed code only •unit-test •RSpec •Needs
better coverage...
Code reading... •To find same pattern that profiler detects
SEGV
Closed 5 SEGVs 4 Fixed 1 Workaround
Workaround Case Help wanted
Workaround Case •Call back image processing progress to Ruby User's
Ruby code RMagick ImageMagick Callback
ruby_stack_length() shows 51119378542 = 47 GB • Invalid stack length
• GC running →SEGV
RMagick is better than ever.
Future...
ImageMagick 7 support
Preparing draft code... now
Plan 1: Split RMagick ver 4.x RMagick ver 3.x ver
3.0 ver 3.1 ver 2.16.1 ImageMagick 7 ImageMagick 6
Plan 2 : Mix both ImageMagick 7 ImageMagick 7 ImageMagick
6 Using many #if defined ...
Plan 3: Bundle both ImageMagick 7 ImageMagick 6
We welcome good ideas for the future
Announcement •RubyData Workshop (Tomorrow, 14:20 ~) •RubyKaigi 2019 Code Party
(Tomorrow, 19:00 ~)
Thank you