Help us understand the problem. What is going on with this article?

Clojureにおいて現在実行中のプログラムの全オブジェクトを得る

More than 5 years have passed since last update.

CROSS2014言語CROSS にて、Smalltalk梅澤さんから、
「現在実行中のプログラムの全オブジェクトを得るには?」
というお題が出題されました。

オブジェクト指向でない言語担当の皆さんは苦戦なさっていたようですが、ClojureはJVMの上で動くので、実はこれは可能です(Clojure CLR等は除外して考えてます…)。

プログラムの外側からヒープダンプをとればいいわけですが、これでは負けた感じなので、アプリケーションに全オブジェクト取得機能を実装してみます。

Oracle JVMでは、HotSpotDiagnosticMxBeanを使ってヒープダンプを出力します。リフレクションを使えば、実行中のプログラムから任意のタイミングで出力可能です。

(let [dump-heap (.getMethod HotSpotDiagnosticMXBean
                            "dumpHeap" (into-array [String Boolean/TYPE]))
      mx-bean  (ManagementFactory/newPlatformMXBeanProxy
                (ManagementFactory/getPlatformMBeanServer)
                "com.sun.management:type=HotSpotDiagnostic"
                HotSpotDiagnosticMXBean)
      hprof-file (io/file (System/getProperty "java.io.tmpdir")
                          (str "clj" (System/currentTimeMillis) ".hprof"))]
  (.invoke dump-heap mx-bean (to-array [(.getAbsolutePath hprof-file) true])))

こんな感じで、ヒープダンプがファイルに出力されます。
あとは、jhatを使えば、ヒープの中身をWebブラウザからみることができます。

が、これも外部ツールに頼っていると、Smalltalkに負けた気がするので、Clojure上でヒープダンプの中身を解析して、インスタンス数を出力できるようにしてみました。
hprofの仕様にしたがい、パーサを適当に書くだけです。

https://gist.github.com/kawasima/8517614

replを起動した直後に実行すると、次のような結果が得られました。

% lein repl
nREPL server started on port 43579
REPL-y 0.1.10
Clojure 1.5.1
    Exit: Control+D or (exit) or (quit)
Commands: (user/help)
    Docs: (doc function-name-here)
          (find-doc "part-of-name-here")
  Source: (source function-name-here)
          (user/sourcery function-name-here)
 Javadoc: (javadoc java-object-or-class-here)
Examples from clojuredocs.org: [clojuredocs or cdoc]
          (user/clojuredocs name-here)
          (user/clojuredocs "ns-here" "name-here")
user=> (load-file "all-instances.clj")
([(primitive array) 99558] [java.lang.String 78632] [clojure.lang.Cons 63579] [clojure.lang.LazySeq 63447] [[Ljava.lang.Object; 52114] [clojure.lang.PersistentHashMap$BitmapIndexedNode 33564] [clojure.lang.Symbol 15636] [java.util.concurrent.atomic.AtomicReference 11201] [clojure.lang.PersistentVector 8120] [java.lang.Long 6839])
515494
true

これで、Clojureの中だけで全インスタンスを表示できるようになりましたね!

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした