Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
7
Help us understand the problem. What are the problem?

More than 5 years have passed since last update.

@kawasima

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

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の仕様にしたがい、パーサを適当に書くだけです。

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
7
Help us understand the problem. What are the problem?