業務アプリケーションを作成する上で、日時を取り扱うのは日常茶飯事だと思います。
例えば、生成した日付オブジェクトを特定のフォーマットパターンで文字列化する という処理の流れは大体どんなシステムでも実施されます。
これを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
はフォーマットパターン(形式)によるメモリサイズの差があまりありません。
まとめとか補足
- 日時をフォーマットするためのクラスのメモリサイズはでかい
SimpleDateFormat
はDateTimeFormatter
に比べてサイズが大きいDateTimeFormatter
はフォーマットパターン(形式)によってメモリサイズが大きく異なるSimpleDateFormat
はフォーマットパターン(形式)によるメモリサイズの差があまりないDateTimeFormatter
はスレッドセーフ。SimpleDateFormat
はスレッドアンセーフ