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

覚えたら書く

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スレッドアンセーフ



関連エントリ