Java 桁の大きいLongがマイナスの数字になってしまう

しょぼい失敗ではありますが。(´・ω・`)

例えば、31日間のミリセカンドを取得すべく下記のように定義したとします。

public static final long THIRTY_ONE_DAYS_MILL_SEC = 31 * 24 * 60 * 60 * 1000;

この数字は、2,678,400,000です。
26億7840万ミリ秒ですね。

ですが、これを実行すると、実際には、THIRTY_ONE_DAYS_MILL_SEC

-1616567296 

という数字が入っています。マイナスの数字になってしまってるんですよー。

なんで?というと、次のようなことが起きているらしい。

①右辺で計算する時はintで計算されている

②intの最大値が int32ビット-2,147,483,648 〜 2,147,483,64

③桁あふれでマイナス値になってしまっている

なので、右辺で計算するときにlongであると宣言してあげないと、 2,678,400,000 にならないらしいのです…。

末尾にLをつけるだけ。

正しくは、下記の通り。


public static final long THIRTY_ONE_DAYS_MILL_SEC = 31 * 24 * 60 * 60 * 1000L;


Ghost Inspector テストの共通化

弊社では、製品の自動テストにGhost Inspectorを利用しています。

ある日のことです。

「この画面消して新しい画面に置き換えるからテストの方も修正しといてよ」

OKまかせろ。

意気揚々とGhost Inspectorのダッシュボードを開きます。

コピペで複製されたものに微妙に改変が加わったり加わらなかったり無造作に乱立したガバガバテスト群を目撃したぼく「がっでむ」

キレた

プログラミングを行う際、共通の処理は関数化を行うなど、なるべく記述を重複させないという方針がございます。
いわゆるDRY原則というやつですね。(厳密には、よく聞くDRY原則は誤認されたものだと言われていますが、話が逸れるので適当なネット記事に任せます)

コードを書いている感覚の少ないGhost Inspectorだって、共通した処理の再利用は重要です。

  • メンテナンスコストの軽減
  • テスト修正時の修正漏れの防止
  • 再利用性の向上
  • 似ているテスト同士の差分確認の容易化

あたりの利点はパッと思いつきますね。特に上2つが現場的には嬉しいところです。

本題

実際に共通化を行っていきます。
今回は、「元々(ほぼ)同じ内容のテストがコピペ乱立していたものを、1つの共通テストを再利用する形に修正し、メンテナンスコストを軽減する」といったシナリオです。泥臭い箇所もございます。

0. 作業フローの確認

  1. 共通化を行いたいテスト内容を持つ、テストA, Bの差分を確認する。
  2. 共通部分を別の「共通テスト」とし、可能なら差分箇所を抽象化する。
  3. テストA, Bは共通テストを参照してテストを行う形に変更する。抽象化した箇所(認証情報やアドレス等)を適宜指定してテストが走るようにする。

1. テスト内容の差分確認

いきなり技術力のカケラも感じないアナログチェックです。

2つのテスト内容を見比べます。

差分のチェックにはdifff《デュフフ》を利用しました。

差分が存在しない場合は、素直にテストを DuplicateMoveしてしまえばOKだと判断できます。

テストの内容に差分が生じている(=異なるテスト項目がある)場合は、内容を吟味して共通テストが吸収したりしなかったりするだけです。何も恐れることはありません。

2. 「共通テスト」の作成

差分の確認ができたら、次は共通で利用するテストを作成します。

共通のテスト項目となる箇所を、個別のテストとして保存します。
DuplicateMoveするなりうまくやりましょう。
わかりやすく「共通テスト」などといったTest Suiteに放り込むと良いでしょう。

テストA, Bそれぞれで利用することになるため、ログイン認証など、テストごとに異なる可能性のある箇所は変数を利用して抽象化します。

参考:Creating and Using Variables – Ghost Inspector

  • テストAとテストBで、同じ名前の変数に値を入れる。
  • 共通テストでは、変数を参照するのみにする(値を入れない)。

このようにすることで、「共通したテスト項目を、複数のアカウントでテストする」といったことが簡単に実現できます。

3. 共通テストを利用したテストの実行

「共通テスト」の作成が完了したら、作成した共通テストを読み込んでテストを実行しましょう。

参考:Modularizing Tests – Reusing Test Steps – Ghost Inspector

Import steps from testすれば、他のテストからテスト項目を読み込んでテストを走らせることができます。

これにより、ログイン情報のみテストA, Bで入力(変数に値を設定)し、画面上のフォームへ値を投入する共通の処理は共通テストで一本化するといったことが可能になります。

このとき、変数に値を設定する処理をテストごとに記述してもいいのですが、Test Suite単位で使うアカウントがほぼ固定であるようなケースも多いと思います。
そういったケースでは、Suite-level Variablesを設定しましょう。より管理が簡単になります。

変数を指定して問題なく動けば作業完了です。

4. その他

テスト毎のStart URLを個別に指定するのも煩雑です。
Suite SettingsTest Defaultsから、Suite単位で共通のStart URLを設定することができます。

※各テストでStart URLを指定しなかった場合のデフォルトの値を指定するだけなので、テストによって別途Start URLを指定している場合でも問題は生じません。

Ghost Inspectorのテスト管理がぐちゃぐちゃで参った人は参考にしてみてください。

※もちろん、ログイン認証部分のテストも共通化してImport steps from testするとよりスマートなのだろうと思いますが、弊社はそこまで綺麗に整えていません……

Android エミュレーターで通信速度の遅い端末を作る Android Studio3.3.2

次の手順で行います。

Tools→

AVD Manager→

各エミュレーターの一覧出てくると思いますが、その鉛筆みたいなアイコンをクリック→

「Show Advanced Settings」をクリック

Netoworkという項目にSpeedとLatencyというのがありますので、それを変更。

・Fullがデフォルトで、PC上でできるかぎりのネットワーク速度を実現

・LTE なんか懐かしい  略称はLong-Term Evolution  らしい。

・HSDPA 多分、昔ハイスピードパケット通信とか言ってたあたりだと思うんですよね。この辺りから、遅さを体感できる…。

・GPRS 3Gぐらいの通信速度

下記の公式情報も参考にしてください。

https://developer.android.com/studio/run/managing-avds?utm_source=android-studio

Ubuntu 18.04 LTS Desktop 日本語Remix セットアップ

ひどい頭痛眼痛に悩まされながら泥沼セットアップを行ったので備忘録的に記事化。

やったこと

  1. UbuntuインストールDVDの作成
  2. インストールDVDからUbuntuをインストール
  3. GPUを積んだので、NVIDIAのドライバをインストール

1. インストールDVDの作成

  1. Ubuntu 18.04 LTS Desktop 日本語Remixのisoイメージダウンロード。
    ubuntu-ja-18.04.2-desktop-amd64.isoを使いました。
  2. 書き込み可能な空のDVDを用意して書き込み可能なドライブに挿入。
  3. isoイメージを右クリック→ディスクへ書き込み→挿入したDVDを選択。
  4. 書き込みが完了したら内容を確認して終了。

参考: Ubuntu 15.10 インストールDVDの作成

2. Ubuntuのインストール

沼①

  1. インストールDVDをセット。
  2. 起動時にF11を長押ししてブートメニューを開く。
    • BIOSがASRockだったため。ブートメニューがBIOS設定内に存在する種類なら、ブートの順位でディスクを入れたドライブを最優先にするだけでOK。
  3. ディスクからの起動を選択し、インストールDVDからUbuntuを起動。
  4. あとはこちらの記事を参考にポチポチとメニューを進めていく。
    Ubuntu 18.04 LTSインストールガイド【スクリーンショットつき解説】
    • このとき、USB起動かUEFIかといった選択肢が出てきたが、UEFIではないので(BIOSなので) USBを選択した。選択肢が「USB」であったのは、DVDドライブがUSB接続の外付けドライブだったことによると思われる。
    • 差分や選択肢の進み方をメモしておく。
      • モード選択
        今回はUbuntuを単体でクリーンインストールするので「Ubuntuをインストール」を選択。
      • インストールタイプ
        通常のインストール。
        アップデートをダウンロード → ✖(ネットワーク接続してなかったので)
        追加のソフトウェア類 → ✖
      • ストレージ設定
        ディスクを削除してインストール。
        インストールの暗号化 → ✖
        LVMを使用 → ✖
  5. インストールが完了するまで待ち、再起動のメニューが出たら再起動。
  6. ログイン後、初期設定
    1. 新機能はスルー。
    2. Livepatchは設定しても良かったかもしれない (特に設定しなかった)。
    3. 改善支援のデータ送信 → ✖

参考: Ubuntu 18.04 LTSインストールガイド【スクリーンショットつき解説】

3. NVIDIAのドライバダウンロード

Windowsマシンなら付属のCDを入れるだけで良さそうなのに、Ubuntuはこのあたり面倒。

※apt-getでドライバをインストールする方法(「NVIDIA apt-get」🔍)もある。今回入れるドライバは、まだダウンロード可能なドライバリストになかったので、runファイルを落としてきて入れる方針。

  1. 積んでいるGPUの種類を調べる。(購入した商品の箱とかに型番書いてあるのでそれ見てもOK)
    1. 情報更新 sudo update-pciids
    2. 情報表示 lspci | grep -i nvidia あるいは lspci | grep -i VGA
      後ろの方の[ ]で挟まれた部分が知りたい情報
  2. NVIDIAのサイトからドライバをダウンロード
    https://www.nvidia.co.jp/Download/index.aspx?lang=jp
    型番選んでダウンロードタイプを選んで検索→ダウンロード。
    ダウンロードタイプはGRDにした(SDがなかった)
  3. NVIDIA-Linux-x86_64-430.14.runというファイルがダウンロードされた。

4. NVIDIAのドライバインストール

沼②

  1. nouveauドライバの無効化
    参考: Ubuntu 18.04 LTS : NVIDIAドライバーをインストール : Server World
    1. 下記コマンドを実行。
      vi /etc/modprobe.d/blacklist-nouveau.conf
    2. 最終行に以下を追記。
      blacklist nouveau
      options nouveau modeset=0
    3. 下記コマンドを実行。
      update-initramfs -u
    4. 下記コマンドを実行(再起動)。
      reboot
  2. gccのインストール
    ※runファイルの実行時に必要だったのでインストール
    1. 下記コマンドの実行。
      sudo apt install build-essential
    2. 下記コマンドの実行(gccの動作確認)。
      gcc --version
  3. ドライバのインストール
    1. 下記コマンドの実行。
      sudo ~/Downloads/NVIDIA-Linux-x86_64-430.14.run
    2. 途中度々選択肢が出るが、基本OK連打になる。
      参考[1]: Deep Learning 用 Workstation 構築記録 その3(OS / ドライバ / CUDA&cuDNN インストール) – Qiita
      参考[2]: Ubuntu 16.04にNVIDIAドライバをインストールする方法 : 回れ右の内輪差
    3. インストールが完了し、黒いターミナルの画面に戻ったら、以下のコマンドを実行(再起動)して終了。
      sudo reboot
  4. 下記のコマンドを実行し、接続が正常に認識されているか確認する。
    nvidia-smi

以上。疲れた。

java.lang.OutOfMemoryError: Failed to allocate a 840012 byte allocation with 555120 free bytes and 538KB until OOM

マイナーな話にはなっちゃうんですが。
AndroidのMapboxでマーカーを追加していて、タブレットで200個ぐらいマーカーを生成する画面でOOMが起こってクラッシュしてしまう、という不具合に遭遇しました。

ググると大きなBitmapをいっぱい追加するとこれが起きやすいという話です。

https://stackoverflow.com/questions/477572/strange-out-of-memory-issue-while-loading-an-image-to-a-bitmap-object

Android Developersの公式でも紹介されていますね。

https://developer.android.com/topic/performance/graphics

皆さん、大体ファイルを読み込んでアプリに表示する系でこれが発生しているようですね。

私はBitmapの生成を、Mapboxのマーカーをタップした時に出るウィンドウのために作ってまして、下記のような感じになります。

public static Bitmap generate(@NonNull View view) {
int measureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
view.measure(measureSpec, measureSpec);

int measuredWidth = view.getMeasuredWidth();
int measuredHeight = view.getMeasuredHeight();

view.layout(0, 0, measuredWidth, measuredHeight);
/Bitmap bitmap = Bitmap.createBitmap(measuredWidth, measuredHeight, Bitmap.Config.ARGB_8888);

//bitmap.eraseColor(Color.TRANSPARENT);
Canvas canvas = new Canvas(bitmap);
view.draw(canvas);
return bitmap;
}

https://docs.mapbox.com/android/maps/examples/symbol-layer-info-window/

コード自体はMapboxの公式サンプルを利用しているだけです。

なので、上述のAndroid DevelopersやStackOverflowにあるような

BitmapFactory.Options

を使ったやり方がどうにもできませんでした…。

なので、

Bitmap bitmap = Bitmap.createBitmap(measuredWidth, measuredHeight, Bitmap.Config.ARGB_8888);

Bitmap bitmap = Bitmap.createBitmap(measuredWidth, measuredHeight, Bitmap.Config.RGB_565);

に変更しました。

ARGB_8888 

にすると、1ピクセルにつき、4バイト使うらしいです。


RGB_565

にすると、1ピクセルにつき、2バイト使います。

透明部分とかが表現できませんが、しょうがない…。

ちなみに、手っ取り早くマニフェストファイルに

<application android:largeHeap=”true” > </appplication>

ってして回避することもできるようですが、これは機種によってできなかったりするらしく、また敗北感あるのでやめました…。