読者です 読者をやめる 読者になる 読者になる

覚えたら書く

IT関係のデベロッパとして日々覚えたことを書き残したいです。 twitter: @yyoshikaw

日付のフォーマット処理する時にどれだけメモリ消費するの?

業務アプリケーションを作成する上で、日時を取り扱うのは日常茶飯事だと思います。
例えば、生成した日付オブジェクトを特定のフォーマットパターンで文字列化する という処理の流れは大体どんなシステムでも実施されます。

これをJavaで実現する場合、現在日時を文字列化するなら以下のようにするのが一般的かと思います。

  • Java7以下の場合
    • java.util.Dateのオブジェクトを生成 ⇒ SimpleDateFormat#format で文字列化
  • Java8以上の場合
    • LocalDateTimeのオブジェクトを生成 ⇒ LocalDateTime#format(DateTimeFormatter) で文字列化


では、日時をフォーマットするための肝となっているSimpleDateFormatやらDateTimeFormatterは、どのくらいメモリを食うのだろうかとふと思い、確認してみました。


今回は以下の2パターンのフォーマットパターンを対象としました

  • yyyy/MM/dd HH:mm:ss
  • yyyy/MM/dd HH


また、メモリ消費量の確認にはJOLを利用しました


LocalDateTimeをDateTimeFormatterでフォーマット

LocalDateTime#nowで現在日時を生成し、DateTimeFormatterを利用してLocalDateTime#formatで所定の形式の文字列にするという流れです


■測定用コード

import org.openjdk.jol.info.GraphLayout;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;


LocalDateTime dateTime = LocalDateTime.now();
DateTimeFormatter format1 = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
DateTimeFormatter format2 = DateTimeFormatter.ofPattern("yyyy/MM/dd");

String dateTimeStr1 = dateTime.format(format1);
String dateTimeStr2 = dateTime.format(format2);


System.out.println("LocalDateTime totalSize(byte) -> " + GraphLayout.parseInstance(dateTime).totalSize());
System.out.println("LocalDateTime footprint -> \n" + GraphLayout.parseInstance(dateTime).toFootprint());

System.out.println("------------");

System.out.println("DateTimeFormatter(yyyy/MM/dd HH:mm:ss) totalSize(byte) -> " + GraphLayout.parseInstance(format1).totalSize());
System.out.println("DateTimeFormatter(yyyy/MM/dd HH:mm:ss) footprint -> \n" + GraphLayout.parseInstance(format1).toFootprint());

System.out.println("------------");

System.out.println("DateTimeFormatter(yyyy/MM/dd) totalSize(byte) -> " + GraphLayout.parseInstance(format2).totalSize());
System.out.println("DateTimeFormatter(yyyy/MM/dd) footprint -> \n" + GraphLayout.parseInstance(format2).toFootprint());

■実行結果

LocalDateTime totalSize(byte) -> 72
LocalDateTime footprint -> 
java.time.LocalDateTime@6576fe71d footprint:
     COUNT       AVG       SUM   DESCRIPTION
         1        24        24   java.time.LocalDate
         1        24        24   java.time.LocalDateTime
         1        24        24   java.time.LocalTime
         3                  72   (total)


------------
DateTimeFormatter(yyyy/MM/dd HH:mm:ss) totalSize(byte) -> 3688
DateTimeFormatter(yyyy/MM/dd HH:mm:ss) footprint -> 
java.time.format.DateTimeFormatter@4361bd48d footprint:
     COUNT       AVG       SUM   DESCRIPTION
        38        34      1296   [C
         1        64        64   [Ljava.time.format.DateTimeFormatterBuilder$DateTimePrinterParser;
        38        24       912   java.lang.String
         7        24       168   java.time.Duration
         1        40        40   java.time.format.DateTimeFormatter
         5        16        80   java.time.format.DateTimeFormatterBuilder$CharLiteralPrinterParser
         1        24        24   java.time.format.DateTimeFormatterBuilder$CompositePrinterParser
         6        32       192   java.time.format.DateTimeFormatterBuilder$NumberPrinterParser
         1        24        24   java.time.format.DecimalStyle
         1        24        24   java.time.format.ResolverStyle
         2        24        48   java.time.format.SignStyle
         6        40       240   java.time.temporal.ChronoField
         7        32       224   java.time.temporal.ChronoUnit
         6        48       288   java.time.temporal.ValueRange
         1        32        32   java.util.Locale
         1        32        32   sun.util.locale.BaseLocale
       122                3688   (total)


------------
DateTimeFormatter(yyyy/MM/dd) totalSize(byte) -> 2184
DateTimeFormatter(yyyy/MM/dd) footprint -> 
java.time.format.DateTimeFormatter@64cee07d footprint:
     COUNT       AVG       SUM   DESCRIPTION
        23        32       752   [C
         1        40        40   [Ljava.time.format.DateTimeFormatterBuilder$DateTimePrinterParser;
        23        24       552   java.lang.String
         4        24        96   java.time.Duration
         1        40        40   java.time.format.DateTimeFormatter
         2        16        32   java.time.format.DateTimeFormatterBuilder$CharLiteralPrinterParser
         1        24        24   java.time.format.DateTimeFormatterBuilder$CompositePrinterParser
         3        32        96   java.time.format.DateTimeFormatterBuilder$NumberPrinterParser
         1        24        24   java.time.format.DecimalStyle
         1        24        24   java.time.format.ResolverStyle
         2        24        48   java.time.format.SignStyle
         3        40       120   java.time.temporal.ChronoField
         4        32       128   java.time.temporal.ChronoUnit
         3        48       144   java.time.temporal.ValueRange
         1        32        32   java.util.Locale
         1        32        32   sun.util.locale.BaseLocale
        74                2184   (total)

結果(メモリサイズ)は以下のようになっています

  • yyyy/MM/dd HH:mm:ss形式のDateTimeFormatter ・・・ 3688byte
  • yyyy/MM/dd 形式のDateTimeFormatter ・・・ 2184byte
  • LocalDateTime ・・・ 72byte

結果を見てわかる通りですが、yyyy/MM/dd HH:mm:ss か yyyy/MM/dd かでDateTimeFormatterのサイズが大きく異なっています


java.util.DateをSimpleDateFormatでフォーマット

java.util.Dateのコンストラクタで現在日時を生成し、SimpleDateFormat#formatで所定の形式の文字列にするという流れです


■測定用コード

import org.openjdk.jol.info.GraphLayout;

import java.text.SimpleDateFormat;
import java.util.Date;


Date dateTime = new Date();
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy/MM/dd");

String dateTimeStr1 = sdf1.format(dateTime);
String dateTimeStr2 = sdf2.format(dateTime);

System.out.println("java.util.Date totalSize(byte) -> " + GraphLayout.parseInstance(dateTime).totalSize());
System.out.println("java.util.Date footprint -> \n" + GraphLayout.parseInstance(dateTime).toFootprint());

System.out.println("------------");

System.out.println("SimpleDateFormat(yyyy/MM/dd HH:mm:ss) totalSize(byte) -> " + GraphLayout.parseInstance(sdf1).totalSize());
System.out.println("SimpleDateFormat(yyyy/MM/dd HH:mm:ss) footprint -> \n" + GraphLayout.parseInstance(sdf1).toFootprint());

System.out.println("------------");

System.out.println("SimpleDateFormat(yyyy/MM/dd) totalSize(byte) -> " + GraphLayout.parseInstance(sdf2).totalSize());
System.out.println("SimpleDateFormat(yyyy/MM/dd) footprint -> \n" + GraphLayout.parseInstance(sdf2).toFootprint());

■実行結果

java.util.Date totalSize(byte) -> 24
java.util.Date footprint -> 
java.util.Date@3f99bd52d footprint:
     COUNT       AVG       SUM   DESCRIPTION
         1        24        24   java.util.Date
         1                  24   (total)


------------
SimpleDateFormat(yyyy/MM/dd HH:mm:ss) totalSize(byte) -> 4616
SimpleDateFormat(yyyy/MM/dd HH:mm:ss) footprint -> 
java.text.SimpleDateFormat@1963006ad footprint:
     COUNT       AVG       SUM   DESCRIPTION
        65        25      1656   [C
         4        58       232   [I
         1        96        96   [J
         6        48       288   [Ljava.lang.String;
         1        40        40   [Z
        63        24      1512   java.lang.String
         1        24        24   java.math.RoundingMode
         1        64        64   java.text.DateFormatSymbols
         1       144       144   java.text.DecimalFormat
         1        64        64   java.text.DecimalFormatSymbols
         1        40        40   java.text.DigitList
         1        64        64   java.text.SimpleDateFormat
         1        24        24   java.util.Currency
         1        24        24   java.util.Date
         1       112       112   java.util.GregorianCalendar
         1        32        32   java.util.Locale
         1        16        16   sun.util.calendar.Gregorian
         1        96        96   sun.util.calendar.Gregorian$Date
         1        56        56   sun.util.calendar.ZoneInfo
         1        32        32   sun.util.locale.BaseLocale
       154                4616   (total)


------------
SimpleDateFormat(yyyy/MM/dd) totalSize(byte) -> 4592
SimpleDateFormat(yyyy/MM/dd) footprint -> 
java.text.SimpleDateFormat@61baa894d footprint:
     COUNT       AVG       SUM   DESCRIPTION
        65        25      1632   [C
         4        58       232   [I
         1        96        96   [J
         6        48       288   [Ljava.lang.String;
         1        40        40   [Z
        63        24      1512   java.lang.String
         1        24        24   java.math.RoundingMode
         1        64        64   java.text.DateFormatSymbols
         1       144       144   java.text.DecimalFormat
         1        64        64   java.text.DecimalFormatSymbols
         1        40        40   java.text.DigitList
         1        64        64   java.text.SimpleDateFormat
         1        24        24   java.util.Currency
         1        24        24   java.util.Date
         1       112       112   java.util.GregorianCalendar
         1        32        32   java.util.Locale
         1        16        16   sun.util.calendar.Gregorian
         1        96        96   sun.util.calendar.Gregorian$Date
         1        56        56   sun.util.calendar.ZoneInfo
         1        32        32   sun.util.locale.BaseLocale
       154                4592   (total)

結果(メモリサイズ)は以下のようになっています

  • yyyy/MM/dd HH:mm:ss形式のSimpleDateFormat ・・・ 4616byte
  • yyyy/MM/dd 形式のSimpleDateFormat ・・・ 4592byte
  • java.util.Date ・・・ 24byte

SimpleDateFormatはフォーマットパターン(形式)によるメモリサイズの差があまりありません。


まとめとか補足

  • 日時をフォーマットするためのクラスのメモリサイズはでかい
  • SimpleDateFormatDateTimeFormatterに比べてサイズが大きい
  • DateTimeFormatterはフォーマットパターン(形式)によってメモリサイズが大きく異なる
  • SimpleDateFormatはフォーマットパターン(形式)によるメモリサイズの差があまりない
  • DateTimeFormatterスレッドセーフSimpleDateFormatスレッドアンセーフ



関連エントリ

Linuxでよくお世話になるスペシャルファイルに関するメモ

開発やテストの際などによくお世話になるLinuxのスペシャルファイル(の中の疑似デバイス)に関するメモです


/dev/null

書かれたデータは捨てられる。

null スペシャルファイルを読むと常に end of file が返される。


/dev/zero

書かれたデータは捨てられる。

常に \0 文字(null 文字)が返される


例えば、以下を実行するとnull文字で埋められた10MBのファイルを生成することができる

dd if=/dev/zero of=sample_10MB.dat bs=10M count=1


/dev/full

/dev/full デバイスへの書き込みは ENOSPC エラーとなり失敗する。
この動作を使ってプログラムがディスクフルのエラーをどのように処理するかをテストできる。

[root]# echo "Hello world" > /dev/full
-bash: echo: write error: デバイスに空き領域がありません


/dev/random

可変長の擬似乱数文字列を生成する(ブロックする)


/dev/urandom

可変長の擬似乱数文字列を生成する(ブロックしない)


例えば、以下を実行するとランダムな値で埋められた10MBのファイルを生成することができる

dd if=/dev/urandom of=sample_10MB.dat bs=10M count=1

KotlinでHello World

Kotlin流行ってますし、そろそろ勉強しようかなと思っている今日この頃。とりあえずHello Worldだけやってみました。

IntelliJ IDEAでKotlinのプロジェクトを作成して以下実行しています。


■サンプルコード

Kotlinのファイル(HelloWorld.kt)を新規作成して以下を記述。
(Javaに比べてかなりシンプルなコードになっています)

package sample.app

fun main(args: Array<String>) {
    println("Hello World!")
}


■実行結果

Hello World

というわけで、Kotlinで無事にHello Worldできました。


その他

IntelliJ IDEAが無しでも以下で試すこともできます

「Deep Learning×画像解析」ライトニングトークイベント

「Deep Learning×画像解析」ライトニングトークイベント by LP-tech に参加してきました。

以下自分用のメモです。


概要

画像解析技術に特化した情報を発信している専門サイトLP-techが主催する、Deep Learning×画像解析に関するLTイベント。

  • 日時: 2017/02/28 19:30~
  • 場所: 東京大学伊藤国際学術研究センターギャラリー1
  • 参加者: エンジニア8割


オープニングトーク「LP-techについて」

島原 佑基 氏 (エルピクセル株式会社)

  • LP-tech
    • 画像処理に関する分かりやすいメディアを作りたかったので作った
    • 現在の記事数は約150
  • ライフサイエンス×画像解析 を盛り上げたい


画像のクラスタリング問題におけるDeepLearningの活用

三好 裕之 氏 (LP-tech編集長, 東京大学計数工学科4年)

  • クラスタリング
    • 特徴量から項目ごとに分類する分類器を作成する手法
    • Traning ⇒ Test
  • クラスタリング応用
    • 音声認識
      • 入力音声特徴量からクラスへのクラス分類ととらえる
    • 顔認識
    • 医用画像判別
    • 細胞認識
  • DeepLearning×クラスタリング
    • 古典的なクラスタリング手法:SVM, K-means ・・・ 一種の特徴量の設定を行わなければならない
    • DeepLeaningによる手法 ・・・ 特徴量の設定必要なし
  • Kaggle competition
    • 多種多様なデータセットが用意されている
    • DICOM画像からどれが危険かを判別するような問題のデータセットも用意されている
  • LP-academy
    • 機械学習の基本について勉強会をやっている


DeepLearningの画像定量への応用 ヒトの目を介さずに画像を分類する

望月 優輝 氏 (LP-techライター, 九州大学理学部生物学科)
 「OpenCV画像解析入門」を運営してます

  • 細胞の種類をChainerで判別してみました
    • EpH4 と HEK293 を対象に判別
  • 薬剤を細胞にかけたら形状が変わったが、客観的な数値で示したい
  • 元画像を5×5=25の格子で分割して学習用データを水増しした(対象が細胞だからできる話)
  • Chainer
    • 層の定義と層の結合
  • もっとロバストな推定を行う場合はより多くの学習データは必須


実際の研究で使えるDeepLearning×画像解析技術の紹介

柏崎 広美 氏 (LP-techライター)

  • ライフサイエンスの研究でもDeppLearningが注目されている
    • 従来手法では、、、
      • データ解析に多大な時間がかかる
      • 解析者により解析結果が変わる
  • ライフサイエンス
    • 動物実験 (in vivo) と 免疫組織化学 (in vitro)
    • 画像データを解析することによって結果が得られる
  • 例1: DeepLearning×動物の行動実験
    • わずか1分間のマウスの行動を人が解析するのにかかる時間が行動実験の障害となっている
    • 行動試験で得られた画像データをDeepLearningにより分類⇒各行動が全体の何%観察されたかが分かる
  • 例2: DeepLearning×神経活動測定
    • 14種類の薬剤を添加後の脳の神経活動を測定
    • 副作用を起こす可能性をDeepLearningを用いて予測する
  • 例3: DeepLearning×免疫組織化学
    • 免疫染色した組織画像⇒組織における免疫細胞の画像からがんの診断を行う
    • DeepLearningで解析した結果と人が主導で解析した結果を比較⇒DeepLearningでの解析結果が人の手動解析の結果が一致した


最新R-CNNの動向について

@Deep Zeon 氏 (ナレッジワークス)

  • YOKOv2
    • 検出速度 64FPS
  • 最近のR-CNN
    • YOLO,SSD, ResNet, R-FCN
    • 動向
      • より高速に、より難しい識別へ、時系列解析との融合
    • 応用
      • リアルタイム検出
      • 軽量化、高速化


DeepLearning×画像生成について

鈴木 雅大 氏 (東京大学工学系研究科 松尾研究室博士2年)
 東大でDeepLearningの講義を担当している

  • 画像を「生成」するには?
    • 新しい「ネコ」の画像を生成したい
      • データの生成源をモデル化
      • 生成モデル
  • 生成モデルでできること
    • 欠損値補完
    • ノイズ除去
    • 異常値検出
  • DeepLearning+生成モデルの代表的アプローチ
    • VAE(変分AE)系
      • 推論分布(エンコーダ)と生成分布(デコーダ)を学習する
      • 画像がぼやける
    • GAN系
      • 生成器と識別器を敵対的に学習させる
      • はっきりした画像を生成できるが、学習のパラメータ調整が難しい
  • 画像から画像の生成
    • GANを使って、ある画像から同じピクセル数の別の画像を生成
    • image-to-image Demoが流行中
  • マルチモーダルな画像生成
    • 文章から画像の生成
    • 画像と属性の双方向の生成
      • 顔から属性、属性から顔が一つのモデルで生成できる
      • 属性を変化させることで、対応する様々な顔を生成できる


DeepMedicによる医療画像解析について

@argon 氏

  • DeepMedicとは何か
    • MRIデータのセグメンテーション用CNNモデル
    • 脳の病変を検出することが目的
  • DeepMedicの特徴
    • ボクセル単位の密なセグメンテーション
    • カーネルサイズを小さく
    • 畳み込み層のみで構成されるCNN
    • 多重解像度CNN
      • 低解像度入力に対するパスを追加
    • 多様なデータに対応
      • MICCAIの2つのコンペで良好な成績をおさめる
  • 実際に動かしてみる
    • 対象データ
      • 病変のサイズは大小様々
    • Residual Network構造



関連エントリ

JSUG勉強会 2017年その2 ~ 脱Spring Boot初心者 に行ってきました

JSUG勉強会に参加してきました

以下自分用のメモ


概要

  • 開催場所 : Pivotal Japan
  • 開催日時 : 2017-02-27(月)19:00 - 21:00


Spring for Spring Boot -Spring Bootユーザーが知るべきSpringの基礎知識-

多田 真敏氏 (株式会社カサレアル、Pivotal認定講師)

Spring Bootから始めた人に知ってほしいSpringの基礎知識を解説

  • Spring Bootは何をしているの?
    • Spring vs Spring Boot
      • Spring Bootになった際に、Configがなくなっただけで後は基本的に同じ
    • Spring Bootの価値
      • デフォルトの設定を提供してくれる。本来のアプリ開発をすぐ始められる
    • Soringにおける設定 ≒ Bean定義
  • Spring の基本!Bean定義を理解しよう
    • Bean ・・・ SpringのDIコンテナで管理しているインスタンス
    • Bean定義=このクラスのインスタンスをBeanとして扱ってとDIコンテナに教えること
    • 各種定義方法
      • (1) アノテーション+コンポーネントスキャン
        • `Configuration + @ComponentScan
        • basePacages属性を指定しなかった場合、この@ComponentScan付与されているクラスが属しているパッケージがスキャン対象となる
      • (2) メソッドによるBean定義
        • Java Config内に@Beanを付与したメソッドを作成。⇒戻り値がBeanになる
    • Spring4.3以降では@Autowiredは省略可能(コンストラクタが1個だけであれば)
    • Java Configの合体
      • @ImportでJava Configを合体できる
      • アプリが大規模になった場合に活躍する。重要。
  • Spring MVC の仕組みを理解しよう
    • Dispatecherですべてのリクエストを受け付けて、Controllerに処理振り分け
    • ViewResolver
      • ビューの論理名からビューの物理名を解決する
      • 各View技術用のViewResolver実装クラスが存在する
        • Thymeleafの場合はThymeleafViewResolver
      • Java8TimeDialectをセットすることでDate and Time APIを解釈できるようになる
    • Spring MVCが動作するにViewResolver以外にも多くのBeanが必要
      • ⇒ @EnableWebMvc
        • 正体は@Import
    • 静的ファイルの扱い
      • WebMvcConfigurerを利用してルーティング設定を追加
        • 通常はWebMvcConfigurerAdaoterクラスを利用する
    • @Configurationの正体は@Component
    • 正体は@Componentなアノテーション
      • @Controller
      • @RestController
      • @Service
      • @Repository
      • etc
    • WebApplicationInitializerでDispatcherServletの設定を記述できる
  • Auto Configurationのソースを読んでSpring Bootを理解しよう
    • 設定の自動化の正体
      • 大量のJava Configクラスがあらかじめ用意されている
      • あるクラスがクラスパス上に存在するかどうかなどの条件で、各Java Condigクラスや各@Beanメソッドを有効化/無効化している
    • メッセージ
      • プロパティファイル名はデフォルトは「messages.properties」
    • 静的ファイル
      • クラスパス直下のstaticフォルダ等が指定されている
    • Bean定義カスタマイズ例
      • (1) application.properties
        • @COnfigurationProperiesなクラス⇒Bean定義で使われる
      • (2) 自分でBean定義する
      • (3) Customizerを利用する
        • XxxCustomizerをBean定義すれば、Auto ConfigurationクラスがDIコンテナから拾ってくれる
  • まとめ
    • 脱Spring Boot初心者となるには、Springの基礎知識が大事
      • Spring Bootを使わずにアプリを作り、Auto Configurationのソースを読みながらアプリをSpring Boot化していこう


実例で学ぶ、明日から使えるSpring Boot Tips

槙 俊明 (Pivotal)

  • Spring Boot is
    • Opinionated Framework on Spring Ecosystem
    • できるだけSpring Boot Wayに乗るべき(むりやり既存のやり方を持ち込むとひずみが生じる)
  • Error画面
    • 以下を用意するだけで良い
      • src/main/resources/static/error/403.html, 404.html, 40x.html, 500.html, 50x.html
    • 動的指定したい場合は以下
      • src/main/resources/templates/error/403., 404., 40x., 500., 50x.
    • application-default.properties
      • server.error.include-stacktrace=always を指定すると ${trace} にStackTraceが入る
    • @ControllerAdviceを指定して、@ExceptionHandlerを使うと全Controllerに適用される
  • profileの指定方法
    • アプリの引数
    • システムプロパティ
    • 環境変数
  • Spring Data RESTによるREST API
    • Repository -> REST API
    • 永続化層に対する操作に対するREST API(HTTP操作)を自動的に提供してくれる
    • Controllerすら書かなくてよくなる
    • コード量が大幅に減る
    • FooRepository#finadName -> /foos/search/findByName?name={name}
    • @RestResource(exported = false) <- 外部に公開したくないエンドポイントの場合
    • その他
      • PagingAndSortingRepository
    • RepositoryEventHandler
      • Repository操作に対するイベントハンドラ。業務ロジックなどを書くことができる
    • トランザクション境界
      • 普通のアプリではServiceでは、@Transactional
      • Spring Data RESTでは、AOPで強引にトランザクション境界を引き延ばせる。が、もしかしたらバッドノウハウかも。
  • CSRF対策
    • Spring Securityを導入するだけでCSRF対策される
    • Ajax / SPA の場合は?
      • CookieCsrdTokenRepositoryを使用する(デフォルトはHttpSessionCsrfTokenRepository)
      • AngularJS
      • Axios
        • PromiseベースのHTTPクライアント
        • X-XSRF-TOKENという名前のCookieが入っていたらHTTPリクエス
  • @EnableOAuth2Sso
    • token = Authoraization Code
    • PrincialExtractor
      • ユーザ情報の作り方などをカスタマイズできる
    • GitHub以外でもOK
      • Authoraization Server ・・・ @EnableAuthoraizationServer
      • アカウントを一元管理できる
  • @ConditionalOnProperty
    • 一つのinterfaceに対して複数の実装を使い分ける方法の一つ
    • 設定の内容に応じて実装が切り替えられる
  • @COnfigurationProperties
    • TypeSafeなプロパティ
    • ConfigurationProcessorを使ってメタ情報も吐くようにしたほうが良い
  • Spring Boot Acturator
    • 1.5からSpring Actuatorでデフォルトでセキュリティ認可が行われる(ROLE_ACTUATOR)



関連エントリ